Android:如何以编程方式获取 SHA1/MD5 指纹?
Posted
技术标签:
【中文标题】Android:如何以编程方式获取 SHA1/MD5 指纹?【英文标题】:Android: How to get SHA1/MD5 fingerprint programmatically? 【发布时间】:2018-03-06 17:40:19 【问题描述】:我正在尝试实现一种与我的后端服务器通信的方法,并确保我的后端只回答,如果它是我的应用程序正在调用。
所以我的想法是,我只需发送带有 HTTPS POST 请求的 SHA1/MD5 指纹并在后端服务器上验证它。如果指纹匹配,服务器会回答。
所以我的第一个问题是:如何在运行时以编程方式获取这些信息?有没有可能?
第二个问题是:有那么容易吗?还是我真的必须设置 OAuth-Server(或使用 google-api)?...问题是,我认为 OAuth 对我的用例来说有点矫枉过正,我不想处理过期/刷新令牌的东西。
【问题讨论】:
"如何在运行时以编程方式获取这些信息?" -- 你还没有说你想得到什么 SHA1/MD5 值。 “有那么容易吗?” - 可能不是。如果这是一个固定值,其他任何人都可以硬编码相同的值。如果这是某种挑战-响应,其他任何人都可以使用相同的数据实现相同的算法。任何人都可以阅读您的 APK。 SHA1 指纹可能就足够了 - 请参阅我的评论 @GabeSechan 回答 @CommonsWare 我有一个要求,我需要放弃我的 api 以便在其他应用程序中使用。从安全和计费的角度来看,我需要确保经过身份验证的应用程序正在访问 API。我想知道 Facebook 和 Google 如何在应用程序创建过程中使用我们提供给他们的 SHA-1。你能分享一些关于实现这一目标的事情吗? @Calvin:我不知道,抱歉。 【参考方案1】:我已经对 Zulqumain Jutt 提出的解决方案进行了补充,以便能够以通用形式获得结果,例如:
KeyHelper:MD5 56:ff:2f:1f:55:fa:79:3b:2c:ba:c9:7d:e3:b1:d2:af
public class KeyHelper
/**
* @param key string like: SHA1, SHA256, MD5.
*/
@SuppressLint("PackageManagerGetSignatures") // test purpose
static void get(Context context, String key)
try
final PackageInfo info = context.getPackageManager()
.getPackageInfo(BuildConfig.APPLICATION_ID, PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures)
final MessageDigest md = MessageDigest.getInstance(key);
md.update(signature.toByteArray());
final byte[] digest = md.digest();
final StringBuilder toRet = new StringBuilder();
for (int i = 0; i < digest.length; i++)
if (i != 0) toRet.append(":");
int b = digest[i] & 0xff;
String hex = Integer.toHexString(b);
if (hex.length() == 1) toRet.append("0");
toRet.append(hex);
Log.e(KeyHelper.class.getSimpleName(), key + " " + toRet.toString());
catch (PackageManager.NameNotFoundException e1)
Log.e("name not found", e1.toString());
catch (NoSuchAlgorithmException e)
Log.e("no such an algorithm", e.toString());
catch (Exception e)
Log.e("exception", e.toString());
【讨论】:
【参考方案2】:您可以生成如下示例中的内容:
private void getKeyHash(String hashStretagy)
PackageInfo info;
try
info = getPackageManager().getPackageInfo(BuildConfig.APPLICATION_ID, PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures)
MessageDigest md;
md = MessageDigest.getInstance(hashStretagy);
md.update(signature.toByteArray());
String something = new String(Base64.encode(md.digest(), 0));
Log.e("KeyHash -->>>>>>>>>>>>" , something);
// Notification.registerGCM(this);
catch (PackageManager.NameNotFoundException e1)
Log.e("name not found" , e1.toString());
catch (NoSuchAlgorithmException e)
Log.e("no such an algorithm" , e.toString());
catch (Exception e)
Log.e("exception" , e.toString());
像这样使用:
getKeyHash("SHA");
getKeyHash("MD5");
第一个答案:您可以使用上述方法,它安全且独特,我一直在使用它。
第二个答案:您可以使用身份验证密钥,但这完全取决于您,您对什么感到满意
【讨论】:
我还没有尝试过,但我想问题是,正如@GabeSechan
所提到的,任何应用程序都可以要求我提供指纹,这对我的目的非常不利。
@Nico 是的,任何人都可以。这实际上就是散列函数的用处——我可以计算文件的 SHA 散列(或 md5 散列)并检查它是否是你所说的,并合理地确定它是同一个文件。它通过公开来进行验证,但出于同样的原因,它无法进行身份验证。
我怎样才能获得发布密钥库哈希来比较?【参考方案3】:
你想做的事是不可能的。您作为 id 发送到服务器的任何内容都可以被另一个应用程序复制。这就是为什么您的用户的密码不在应用程序中 - 来自外部来源的密码是确保请求有效的唯一方法。这只能证明 user 是有效的,而不是它来自您的应用程序。
【讨论】:
从数学上讲,仅根据外部代理提供给您的信息,无法证明外部代理的身份。其他任何人都可以通过获取您的应用程序的 sha 指纹并使用它来谎称他们的 sha 指纹是什么。 正确的做法是对您的用户进行身份验证,并提供一组 API,只允许他们执行您希望他们能够执行的操作(每个都进行适当的授权检查)。然后,您无需关心他们是否在使用您的应用程序。如果他们真的想全力以赴写自己的客户,谁在乎呢? @GabeSechan 在我的工作流程中类似的情况下,我无法让用户输入密码。我需要应用程序供应商访问我的服务器 API,但是,我的服务器根本没有用户信息。我有点许可应用程序供应商将我的 API 用于他们特定的 1 应用程序。我不愿意在应用程序中硬编码一些东西。我可以从 android 应用程序密钥库中派生一些东西,并且服务器上已经有一些东西来知道请求来自真实的供应商。 @GabeSechan 要获取 SHA-1 指纹并在后端注册它,您需要用于签署应用程序的密钥库文件、密钥库密码和别名/密码的组合。如果攻击者设法窃取您的密钥库,您可能会遇到更大的问题,这就像从服务器窃取私有证书一样。我并不是说这是最终的身份验证协议,但在我看来它非常安全,这就是 GCP 使用它的原因。 @GabeSechan 如果这正如你所说的那样简单,那么为什么没有很多报告谈论使用 GCP 的大型应用程序的 API 配额泄漏?如果窃取 API 配额如此容易,没有人会使用 GCP,如果是这种情况,为什么 Google 会选择这种身份验证方法?【参考方案4】:Kotlin 版本的 Artur 密钥字符串示例:“SHA1”或“SHA256”或“MD5”。
fun getSig(context: Context, key: String)
try
val info = context.packageManager.getPackageInfo(
BuildConfig.APPLICATION_ID,
PackageManager.GET_SIGNATURES
)
for (signature in info.signatures)
val md = MessageDigest.getInstance(key)
md.update(signature.toByteArray())
val digest = md.digest()
val toRet = StringBuilder()
for (i in digest.indices)
if (i != 0) toRet.append(":")
val b = digest[i].toInt() and 0xff
val hex = Integer.toHexString(b)
if (hex.length == 1) toRet.append("0")
toRet.append(hex)
val s = toRet.toString()
Log.e("sig", s)
catch (e1: PackageManager.NameNotFoundException)
Log.e("name not found", e1.toString())
catch (e: NoSuchAlgorithmException)
Log.e("no such an algorithm", e.toString())
catch (e: Exception)
Log.e("exception", e.toString())
【讨论】:
以上是关于Android:如何以编程方式获取 SHA1/MD5 指纹?的主要内容,如果未能解决你的问题,请参考以下文章
以编程方式获取 Android 手机型号,如何在 android 中以编程方式获取设备名称和型号?
使用CMD命令查看Android应用签名证书的SHA1、MD5、SHA256值
如何以编程方式获取 android 设备屏幕截图? [复制]
如何以编程方式获取android手机的IP地址......? [复制]