Google 如何在 API 调用中验证 SHA1 和包名称?

在 API 控制台中注册 Android 应用以进行 Google API 访问时,您必须输入应用 SHA1 证书指纹和应用的程序包名称。

现在我想知道当api调用只是简单的HTTP请求时,Google如何验证此值是否正确(在最简单的情况下,当您不使用其API客户端时,可能会附加一些标头值)?进行 API 调用时,您必须提供 API 密钥,但这并不能证明输入的值是正确的。


答案 1

您可以非常轻松地获取已安装应用程序的软件包名称以及sha 1指纹。

private void printSha1() {
    List<ApplicationInfo> mAppList = getPackageManager().getInstalledApplications(0);
    for (ApplicationInfo info :mAppList) {
        Log.d(TAG, "Package Name: " + info.packageName);
        Log.d(TAG, "Sha1: " + getCertificateSHA1Fingerprint(info.packageName));
    }
}

private String getCertificateSHA1Fingerprint(String packageName) {
    PackageManager pm = getPackageManager();
    int flags = PackageManager.GET_SIGNATURES;
    PackageInfo packageInfo = null;
    try {
        packageInfo = pm.getPackageInfo(packageName, flags);
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
    Signature[] signatures = packageInfo.signatures;
    byte[] cert = signatures[0].toByteArray();
    InputStream input = new ByteArrayInputStream(cert);
    CertificateFactory cf = null;
    try {
        cf = CertificateFactory.getInstance("X509");
    } catch (CertificateException e) {
        e.printStackTrace();
    }
    X509Certificate c = null;
    try {
        c = (X509Certificate) cf.generateCertificate(input);
    } catch (CertificateException e) {
        e.printStackTrace();
    }
    String hexString = null;
    try {
        MessageDigest md = MessageDigest.getInstance("SHA1");
        byte[] publicKey = md.digest(c.getEncoded());
        hexString = byte2HexFormatted(publicKey);
    } catch (NoSuchAlgorithmException e1) {
        e1.printStackTrace();
    } catch (CertificateEncodingException e) {
        e.printStackTrace();
    }
    return hexString;
}

public static 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();
}

如果运行此代码,它将打印包名称及其 sha 1 打印。这是您在创建 API 密钥时提供的两项内容,因此 Google 会将这两项内容与它生成的密钥进行映射。

正如你可以看到它可以访问包名称及其SHA 1打印的另一个剩余的东西是API密钥,你通过你的代码或通过xml(清单,单独的xml配置文件)提供给必要的库或其他应用程序(Google Play服务)。

因此,每当Google为您提供任何东西时,它都可以检查当您从API控制台生成密钥时生成的相关映射。

包名称的代码取自此处


答案 2

如果您没有使用Google Utils / SDK / API客户端,则必须手动传递这些标头。

如果您已经限制了Android或ios应用程序的API密钥,则必须传递以下标头 -

安卓标头:

{
  'x-android-package': 'com.example',
  'x-android-cert': '50FEC39F742F3DF212BDC2131A99C7D3C82086F6'
}

此处标头的值是没有分号的签名密钥的 SHA1 指纹。x-android-cert

要从密钥库文件中获取 SHA1 指纹,

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android

要从签名的apk /捆绑包中获取SHA1指纹-

keytool -printcert -jarfile ~/Downloads/app-release.aab

keytool -printcert -jarfile ~/Downloads/app-release.apk

ios 标头:

{
  'x-ios-bundle-identifier': 'com.example' 
}

下面是捆绑标识符。com.example

下面是Java中的类,我认为它在本机Places SDK中做了相同的工作 -

/**
 * Intercepts requests and provides Android-specific headers so that API key restrictions can be
 * enforced.
 */
public class AndroidAuthenticationInterceptor implements Interceptor {

  ...

  @NotNull
  @Override
  public Response intercept(@NotNull Chain chain) throws IOException {
    ...

    final Request.Builder builder = chain.request().newBuilder();
    if (config.packageName != null) {
      builder.addHeader(HttpHeaders.X_ANDROID_PACKAGE, config.packageName);
    }

    if (config.certFingerprint != null) {
      builder.addHeader(HttpHeaders.X_ANDROID_CERT, config.certFingerprint);
    }

    return chain.proceed(builder.build());
  }
}

参考资料-

  1. 限制使用 Google API 的 Android 密钥
  2. 如何确定使用哪个密钥库对应用程序进行签名?
  3. https://developers.google.com/maps/api-security-best-practices
  4. https://github.com/googlemaps/google-maps-services-java/blob/9852dbae5d2c10897ad7a8dd4befcd171a2cd48e/src/main/java/com/google/maps/android/AndroidAuthenticationInterceptor.java
  5. https://github.com/googlemaps/google-maps-services-java/blob/main/src/main/java/com/google/maps/internal/HttpHeaders.java