Android簽名證書完整性校驗(適配Android P)

前幾天收到一份App安全檢測報告,其中一項是缺少自身簽名完整性校驗。

漏洞描述:Android系統(tǒng)使用JAR包的簽名機制對APK進行完整性保護,確保APK在不安全的網(wǎng)絡(luò)傳輸時的完整性得到保護。但Android系統(tǒng)沒有對數(shù)字簽名的頒發(fā)者進行管理,任何人都可以生成數(shù)字簽名,并使用該簽名對APK包進行重新簽名。如果App本身不對自身的簽名來源進行有效的完整性檢查,攻擊者可以篡改應(yīng)用(插入惡意代碼、木馬、后門、廣告等),重新簽名并且二次發(fā)布,導(dǎo)致應(yīng)用程序完整性被破壞

public class SignCheckUtil {

    private Context context;
    private String cer = null;
    private String type = "SHA1";
    private String sha1RealCer = "簽名SHA1值";
    private String md5RealCer = "簽名MD5";
    private static final String TAG = "sign";

    public SignCheckUtil(Context context,String type) {
        this.context = context;
        this.type = type;
    }



    /**
     * 獲取應(yīng)用的簽名
     *
     * @return
     */
    public String getCertificateSHA1Fingerprint() {
        String hexString = "";


        //獲取包管理器
        PackageManager pm = context.getPackageManager();

        //獲取當(dāng)前要獲取 SHA1 值的包名,也可以用其他的包名,但需要注意,
        //在用其他包名的前提是,此方法傳遞的參數(shù) Context 應(yīng)該是對應(yīng)包的上下文。
        String packageName = context.getPackageName();

        //簽名信息
        Signature[] signatures = null;

        try {
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
                PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNING_CERTIFICATES);
                SigningInfo signingInfo = packageInfo.signingInfo;
                signatures = signingInfo.getApkContentsSigners();
            } else {
                //獲得包的所有內(nèi)容信息類
                PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
                signatures = packageInfo.signatures;
            }


//        Signature[] signatures = packageInfo.signatures;
            byte[] cert = signatures[0].toByteArray();

            //將簽名轉(zhuǎn)換為字節(jié)數(shù)組流
            InputStream input = new ByteArrayInputStream(cert);

            //證書工廠類,這個類實現(xiàn)了出廠合格證算法的功能
            CertificateFactory cf = CertificateFactory.getInstance("X509");

            //X509 證書,X.509 是一種非常通用的證書格式
            X509Certificate c = null;
            c = (X509Certificate) cf.generateCertificate(input);


            //加密算法的類,這里的參數(shù)可以使 MD4,MD5 等加密算法
            MessageDigest md = MessageDigest.getInstance(type);

            //獲得公鑰
            byte[] publicKey = md.digest(c.getEncoded());

            //字節(jié)到十六進制的格式轉(zhuǎn)換
            hexString = byte2HexFormatted(publicKey);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        } catch (CertificateEncodingException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return hexString.trim();
    }

    //這里是將獲取到得編碼進行16 進制轉(zhuǎn)換
    private String byte2HexFormatted(byte[] arr) {

        StringBuilder str = new StringBuilder(arr.length * 2);

        for (int i = 0; i < arr.length; i++) {
            String h = Integer.toHexString(arr[i]);
            int l = h.length();
            if (l == 1)
                h = "0" + h;
            if (l > 2)
                h = h.substring(l - 2, l);
            str.append(h.toUpperCase());
            if (i < (arr.length - 1))
                str.append(':');
        }
        return str.toString();
    }

    /**
     * 檢測簽名是否正確
     *
     * @return true 簽名正常 false 簽名不正常
     */
    public boolean check() {

        if (this.sha1RealCer != null || md5RealCer!= null) {
            cer = getCertificateSHA1Fingerprint();
//            Log.d(TAG, "check: " + cer);
            if ((TextUtils.equals(type,"SHA1") && this.cer.equals(this.sha1RealCer)) || (TextUtils.equals(type,"MD5") && this.cer.equals(this.md5RealCer))) {
                return true;
            }
        }
        return false;
    }
}

使用

public void checkSign(View view) {
        SignCheckUtil signCheckUtil = new SignCheckUtil(mContext,"MD5");
        //SignCheckUtil signCheckUtil = new SignCheckUtil(mContext,"SHA1");
        if (signCheckUtil.check()) {
            showToast("簽名正確");
        } else {
            showToast("簽名錯誤");
        }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容