android - 使用自签名证书在 android 中创建安全的客户端-服务器连接

标签 android security ssl

我正在开发企业 android 应用程序,因此有必要在我的测试阶段在客户端(android 模拟器/测试手机)和服务器之间创建安全连接,即使服务器的证书是自签名的,而合法证书正在被公司收购(目前我无法控制)。

我需要信任服务器的自签名证书及其证书颁发机构,当然,android 操作系统 native 不信任它。我正在关注 google's suggestion for creating an HTTPS environment in this scenario几乎一字不差。

我目前面临的问题是我无法访问我的 .crt 文件,如 google 示例中的这一行所示:

InputStream caInput = new BufferedInputStream(
    new FileInputStream("load-der.crt"));

代替上面的,我使用:

InputStream caInput = new BufferedInputStream(
getResources().openRawResource(R.raw.mycrtfile));

打开从mycrtfile.crt导出的InputStream,其中.crt文件存在于/res/raw/mycrtfile .crt。但是,我在该行收到了一个 NullPointerException

有没有更好的方法来存储和访问我需要作为 InputStreamFileInputStream 加载的证书文件,而不是作为存储在 res目录?

最佳答案

有多种方法可以解决您的问题,但这是我使用的方法: 所有步骤都在这个链接http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/但有些部分可能会混淆,所以我将解释所有过程:

1.-将您的 mycrtfile.crt 存储在已知路径中,我会说 c:BKS/mycrtfile.crt。

2.-要创建 BKS 或 keystore ,您需要文件 bcprov-jdk15on-146.jar,此类将为我们完成所有工作,有不同的版本,但这个版本对我有用 http://www.bouncycastle.org/download/bcprov-jdk15on-146.jar也将此文件存储到 C:BKS/

3.-现在您将使用 Keytool(keytool 随 Java SDK 一起提供。您应该在包含 javac 的目录中找到它)来生成我们的 keystore 并确保其正常工作,请转到您的 cmd 并键入“Keytool ",您将看到可用的命令,这意味着正在运行,或者您可以通过“C:\Program Files (x86)\Java\jre7\bin>keytool”访问。

4.-现在一切就绪,我们可以使用此命令行生成 keystore :

keytool -importcert -v -trustcacerts -file "c:\BKS/mycrtfile.crt"-别名证书 -keystore "c:\BKS/keystore.bks"-provider org.bouncycaSTLe.jce.provider.BouncyCaSTLeProvider -providerpath "c:\BKS/prov-jdk15on-146.jar"-storetype BKS -storepass mysecret

让我们看看这一行是什么(我在这部分真的很困惑): -"c:\BKS/mycrtfile.crt":这是证书的路径。 -"c:\BKS/keystore.bks"这是我们存储 keystore 的路径,你可以更改我使用 keystore 的输出名称,只要确保扩展文件是.bks -"c:\BKS/prov-jdk15on-146.jar":这是完成所有工作的文件路径。 -mysecret:这是使用 keystore 的密码,您将需要此密码,所以不要忘记这一点。

已编辑:
4.1- 还使用此命令行验证证书是否已正确导入 keystore :

keytool -list -keystore "res/raw/Keystore.bks"-provider org.bouncycaSTLe.jce.provider.BouncyCaSTLeProvider -providerpath "c:\BKS/prov-jdk15on-146.jar"-storetype BKS -storepass mysecret

4.2- 之后您应该会看到如下输出:

RootCA,2010 年 10 月 22 日,trustedCertEntry,指纹 (MD5):24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93 中级 CA,2010 年 10 月 22 日,trustedCertEntry,指纹 (MD5):98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
这意味着它已正确导入。

5.- 在此之后,如果您转到 BKS 文件夹,您将看到一个 Keystore.bks 文件,这意味着我们正在路上。

6.- 现在让我们转到 ANDROID 部分。在您的项目中,检查您是否有“原始”文件夹,如果没有,则必须在 Yourproject/res/raw 中创建此文件夹。

7.-将您的 Keystore.bks 文件复制到原始文件夹中。现在一切就绪,让我们转到代码。

8.--- 现在我们将创建一个类来读取和信任我们的 keystore :

import java.io.InputStream;
import java.security.KeyStore;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import com.futureconcepts.anonymous.R;
import android.content.Context;


public class Client extends  DefaultHttpClient   {
final Context context;
  public Client(Context context) {
      this.context = context;
  }

  @Override
  protected ClientConnectionManager createClientConnectionManager() {
      SchemeRegistry registry = new SchemeRegistry();
      registry.register(new Scheme("http", 
      PlainSocketFactory.getSocketFactory(), 80));
      // Register for port 443 our SSLSocketFactory with our keystore
      // to the ConnectionManager
      registry.register(new Scheme("https", newSslSocketFactory(),443));

    HttpParams httpParams = new BasicHttpParams();
     HttpConnectionParams.setConnectionTimeout(httpParams,9000);
     HttpConnectionParams.setSoTimeout(httpParams, 9000);

      return new SingleClientConnManager(httpParams, registry);
  }


  private SSLSocketFactory newSslSocketFactory() {
      try {

          // Get an instance of the Bouncy Castle KeyStore format
            KeyStore trusted = KeyStore.getInstance("BKS");//put BKS literal  
            // Get the raw resource, which contains the keystore with
            // your trusted certificates (root and any intermediate certs)
            InputStream in =context.getResources().openRawResource(R.raw.keystore);
            try {
                // Initialize the keystore with the provided trusted certificates
                // Also provide the password of the keystore
                trusted.load(in, "mysecret".toCharArray());
            } finally {
                in.close();
            }
          // Pass the keystore to the SSLSocketFactory. The factory is responsible
          // for the verification of the server certificate.
          SSLSocketFactory sf = new SSLSocketFactory(trusted);
          // Hostname verification from certificate

           sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
          return sf;
      } catch (Exception e) {
          throw new AssertionError(e);
      }
  }

}

9.我们现在完成了请求,只需执行以下操作: HttpClient 客户端= 新客户端(this); ///设置你的 Httpclient.

就是这样,现在您将只信任您的证书。我希望这个解释对您或遇到相同问题的任何人有所帮助。

关于android - 使用自签名证书在 android 中创建安全的客户端-服务器连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18346249/

相关文章:

javascript - 用于清除 TextView 文本的 Android Studio 按钮

Android:罕见且不可重现的 ClassNotFoundException

javascript - 如何保护 EmberJS 或任何 Javascript MVC 框架?

amazon-web-services - 在 AWS API Gateway 中,如何将 HTTPS 密码限制为提供完美前向保密的密码?

c# - 在没有 ssl 证书的服务器上为新的 mvc3 站点启用 http

android - 如何在 jquery mobile 上使用自定义图标?

android - Android 应用程序被杀死时如何处理离线 firebase 数据库?

c# - Rijndael 加密函数 - Key/IV/Salt 设置

C++专业代码分析工具

ssl - 定制证书