首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在API 28中使用PackageInfo.GET_SIGNING_CERTIFICATES?

如何在API 28中使用PackageInfo.GET_SIGNING_CERTIFICATES?
EN

Stack Overflow用户
提问于 2018-08-27 14:46:26
回答 6查看 14.5K关注 0票数 17

PackageManager.GET_SIGNATURES的文档中说“这个常量在APILevel28中被废弃了。请使用GET_SIGNING_CERTIFICATES”。

不幸的是,它并不安全,很容易被黑客入侵。

如何使用Android引入的新"GET_SIGNING_CERTIFICATES“?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2018-11-21 07:31:49

API28或更高版本的中,您也应该检查是否为。

这一职能将完成以下工作:

(为Android9.0及更低版本工作)

代码语言:javascript
复制
fun getApplicationSignature(packageName: String = context.packageName): List<String> {
    val signatureList: List<String>
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            // New signature
            val sig = context.packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES).signingInfo
            signatureList = if (sig.hasMultipleSigners()) {
                // Send all with apkContentsSigners
                sig.apkContentsSigners.map {
                    val digest = MessageDigest.getInstance("SHA")
                    digest.update(it.toByteArray())
                    bytesToHex(digest.digest())
                }
            } else {
                // Send one with signingCertificateHistory
                sig.signingCertificateHistory.map {
                    val digest = MessageDigest.getInstance("SHA")
                    digest.update(it.toByteArray())
                    bytesToHex(digest.digest())
                }
            }
        } else {
            val sig = context.packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures
            signatureList = sig.map {
                val digest = MessageDigest.getInstance("SHA")
                digest.update(it.toByteArray())
                bytesToHex(digest.digest())
            }
        }

        return signatureList
    } catch (e: Exception) {
        // Handle error
    }
    return emptyList()
}

byteToHex是:

代码语言:javascript
复制
fun bytesToHex(bytes: ByteArray): String {
    val hexArray = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F')
    val hexChars = CharArray(bytes.size * 2)
    var v: Int
    for (j in bytes.indices) {
        v = bytes[j].toInt() and 0xFF
        hexChars[j * 2] = hexArray[v.ushr(4)]
        hexChars[j * 2 + 1] = hexArray[v and 0x0F]
    }
    return String(hexChars)
}
票数 29
EN

Stack Overflow用户

发布于 2019-05-28 21:37:54

TL;DR如果您的用例是您正在验证调用包的签名,只要您验证包管理器返回的所有签名者(而不是在找到信任的签名时尽早停止),仍然可以在预api 28中安全地使用GET_SIGNATURES。事实上,谷歌用棒棒糖(https://android.googlesource.com/platform/libcore/+/f8986a989759c43c155ae64f9a3b36f670602521)修补了它。

详细信息:--我相信您对GET_SIGNATURES容易被黑客攻击的评论是基于这个漏洞(https://www.blackhat.com/docs/us-14/materials/us-14-Forristal-Android-FakeID-Vulnerability-Walkthrough.pdf)。在返回apk签名者之前,android不验证信任链。

只有当您有这样的代码时,这才是一个问题:

代码语言:javascript
复制
    private boolean validateCallingPackage(String: packageName) {
        PackageInfo packageInfo;
        try {
            packageInfo = context.getPackageManager().getPackageInfo(
                packageName,
                PackageManager.GET_SIGNATURES);
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }


        for (Signature signature : packageInfo.signatures) {
            String hashedSignature = Utility.sha256hash(signature.toByteArray());
            if (validAppSignatureHashes.contains(hashedSignature)) {
              return true;  //THIS is the problematic code
            }
        }
        return false
    }

如果代码找到与您的白名单中的证书匹配的证书,则该代码将返回true。对于android漏洞,如果签名包含来自恶意签名者的签名,则代码仍然返回true。

此漏洞的缓解方法是检查从包管理器返回的所有签名,如果白名单中没有这些签名,则返回false。即

代码语言:javascript
复制
    private boolean validateCallingPackage(String: packageName) {
        ...

        for (Signature signature : packageInfo.signatures) {
            String hashedSignature = Utility.sha256hash(signature.toByteArray());
            if (!validAppSignatureHashes.contains(hashedSignature)) {
              return false; //FIXED
            }
        }
        return true
    }
票数 9
EN

Stack Overflow用户

发布于 2018-08-27 16:00:24

我的解决办法是:

在gradle构建集"compileSdkVersion 28“和"targetSdkVersion 28”中,现在可以使用以下示例代码:

代码语言:javascript
复制
try {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        @SuppressLint("WrongConstant") final PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNING_CERTIFICATES);
        final Signature[] signatures = packageInfo.signingInfo.getApkContentsSigners();
        final MessageDigest md = MessageDigest.getInstance("SHA");
        for (Signature signature : signatures) {
            md.update(signature.toByteArray());
            final String signatureBase64 = new String(Base64.encode(md.digest(), Base64.DEFAULT));
            Log.d("Signature Base64", signatureBase64);
        }
    }
} catch (PackageManager.NameNotFoundException | NoSuchAlgorithmException e) {
    e.printStackTrace();
}

奇怪的是,如果Android不识别常量GET_SIGNING_CERTIFICATES,可以使用@SuppressLint ("WrongConstant")注释。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52041805

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档