PackageManager.GET_SIGNATURES的文档中说“这个常量在APILevel28中被废弃了。请使用GET_SIGNING_CERTIFICATES”。
不幸的是,它并不安全,很容易被黑客入侵。
如何使用Android引入的新"GET_SIGNING_CERTIFICATES“?
发布于 2018-11-21 07:31:49
在API28或更高版本的中,您也应该检查是否为。
这一职能将完成以下工作:
(为Android9.0及更低版本工作)
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是:
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)
}发布于 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不验证信任链。
只有当您有这样的代码时,这才是一个问题:
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。即
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
}发布于 2018-08-27 16:00:24
我的解决办法是:
在gradle构建集"compileSdkVersion 28“和"targetSdkVersion 28”中,现在可以使用以下示例代码:
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")注释。
https://stackoverflow.com/questions/52041805
复制相似问题