代码之家  ›  专栏  ›  技术社区  ›  KDEx

使用密钥库确认APK身份

  •  1
  • KDEx  · 技术社区  · 12 年前

    我正在构建一个与在线网络服务通信的Android应用程序。我计划在GitHub上发布应用程序的源代码。对于我的生产版本,它将利用我的个人网络服务,我想只允许我的数字签名apk连接。

    是否可以请求APK的密钥库并从该密钥库中确认用户名/密码?

    如果这不可能,我还能如何生产此功能?

    编辑:

    我已经在课堂上读了 Certificate 看起来我可以使用公钥/私钥来确认身份。但我仍然不确定是否能实施

    2 回复  |  直到 12 年前
        1
  •  1
  •   323go    12 年前

    我用这个--

        static public String getPackageFingerPrint( Context ctx ) {
            PackageManager pm = ctx.getPackageManager();
            String packageName = ctx.getPackageName();
            int flags = PackageManager.GET_SIGNATURES;
    
            PackageInfo packageInfo = null;
    
            try {
                    packageInfo = pm.getPackageInfo(packageName, flags);
            } catch (NameNotFoundException e) {
                    return "";
            }
            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) {
                    return "";
            }
            X509Certificate c = null;
            try {
                    c = (X509Certificate) cf.generateCertificate(input);
            } catch (CertificateException e) {
                    return "";
            }
    
    
            try {
                MessageDigest md = MessageDigest.getInstance("SHA1");
                byte[] publicKey = md.digest(c.getPublicKey().getEncoded());
    
    
                StringBuffer hexString = new StringBuffer();
                for (int i=0;i<publicKey.length;i++) {
                    String appendString = Integer.toHexString(0xFF & publicKey[i]);
                    if(appendString.length()==1)hexString.append("0");
                    hexString.append(appendString);
                    }
    
    
                return hexString.toString();
    
            } catch (NoSuchAlgorithmException e1) {
                return "";
            } 
        }
    

    我看到你的方法存在的问题是,任何人都可以确定包指纹或你的包,并将其发送到你的网络服务。更好的可能性是使用挑战-响应机制:您的web服务向您发送一个唯一的会话令牌,您的应用程序使用共享算法对其进行加密或摘要,然后将此加密令牌发送回您的服务进行验证。当然,您不希望将该算法发布到github。

        2
  •  0
  •   dst    12 年前

    您不能将web服务限制为使用特定密钥签名的apk。

    你的apk的签名会经过安卓操作系统的验证,不会直接与设备连接的网络服务共享。即使你从密钥库中读取签名并将其与请求一起发送,攻击者也可能只发送相同的签名(例如,相同的字节流),而无法访问你的私钥。他只需要获取您已签名的apk,从密钥库中读取字节(或听取合法请求)并破坏数据。

    您需要签署单独的请求才能获得一定的安全级别。但是,如果你在发布版本中保留私钥(该密钥未在gitHub上分发),并使用该密钥签署请求,那么你就不安全了,因为私钥是作为apk的一部分分发的,因此很容易被提取。

    以任何方式,您的API都可以被其他apk访问。

    然而,可能还有另一种方法来限制你的API,例如使用许可证令牌等。在这种情况下,你可能不在乎用户是否自己构建apk,只要他有有效的许可证令牌。如果许可证令牌被利用和分发,您可能会对该许可证令牌上的大量流量做出反应,例如阻止其进行进一步的请求。由于我不使用Google Play,我不确定它们能在多大程度上从你的服务器上得到验证,但也许 application licensing portal 是搜索合适代币的良好起点。