Android:使用 HttpsURLConnection 的 HTTPS (SSL) 连接 [英] Android: HTTPS (SSL) connection using HttpsURLConnection

查看:28
本文介绍了Android:使用 HttpsURLConnection 的 HTTPS (SSL) 连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有 2 个应用程序,一个是 Servlet/Tomcat 服务器,另一个是 Android 应用程序.

I have 2 apps, one is a Servlet/Tomcat Server, and the other is an Android app.

我想使用 HttpURLConnection 在两者之间发送和接收 XML.

I want to use HttpURLConnection to send and receive XML between both.

代码:

    private String sendPostRequest(String requeststring) {

    DataInputStream dis = null;
    StringBuffer messagebuffer = new StringBuffer();

    HttpURLConnection urlConnection = null;

    try {
        URL url = new URL(this.getServerURL());

        urlConnection = (HttpURLConnection) url.openConnection();           

        urlConnection.setDoOutput(true);

        urlConnection.setRequestMethod("POST");

        OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());

        out.write(requeststring.getBytes());

        out.flush();

        InputStream in = new BufferedInputStream(urlConnection.getInputStream());

        dis = new DataInputStream(in);

        int ch;

        long len = urlConnection.getContentLength();

        if (len != -1) {

            for (int i = 0; i < len; i++)

                if ((ch = dis.read()) != -1) {

                    messagebuffer.append((char) ch);
                }
        } else {

            while ((ch = dis.read()) != -1)
                messagebuffer.append((char) ch);
        }

        dis.close();

    } catch (Exception e) {

        e.printStackTrace();

    } finally {

        urlConnection.disconnect();
    }

    return messagebuffer.toString();
}

现在,我需要使用 SSL 来发送 XML 以确保安全.

Now, I need to use SSL to send the XMLs for security.

首先,我使用 Java Keytool 生成 .keystore 文件.

First, I use Java Keytool to generate the .keystore file.

Keytool  -keygen -alias tomcat -keyalg RSA

然后我把XML Code放在Tomcat的server.xml文件中使用SSL

Then I put the XML Code on server.xml file of Tomcat to use SSL

<Connector 
port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
keystoreFile="c:/Documents and Settings/MyUser/.keystore"
keystorePass="password"
clientAuth="false" sslProtocol="TLS" 
/>

然后,我将其更改为 HttpURLConnection 为 HttpsURLConnection

Then, I change it the HttpURLConnection for HttpsURLConnection

    private String sendPostRequest(String requeststring) {

    DataInputStream dis = null;
    StringBuffer messagebuffer = new StringBuffer();

    HttpURLConnection urlConnection = null;

    //Conexion por HTTPS
    HttpsURLConnection urlHttpsConnection = null;

    try {
        URL url = new URL(this.getServerURL());

        //urlConnection = (HttpURLConnection) url.openConnection();         

        //Si necesito usar HTTPS
        if (url.getProtocol().toLowerCase().equals("https")) {

            trustAllHosts();

            //Creo la Conexion
            urlHttpsConnection = (HttpsURLConnection) url.openConnection();

            //Seteo la verificacion para que NO verifique nada!!
            urlHttpsConnection.setHostnameVerifier(DO_NOT_VERIFY);

            //Asigno a la otra variable para usar simpre la mism
            urlConnection = urlHttpsConnection;

        } else {

            urlConnection = (HttpURLConnection) url.openConnection();
        }

//Do the same like up

并添加一个 trustAllHosts 方法来信任每个服务器(不检查任何证书)

and add a trustAllHosts method to Trust every server (dont check for any certificate)

private static void trustAllHosts() {

    X509TrustManager easyTrustManager = new X509TrustManager() {

        public void checkClientTrusted(
                X509Certificate[] chain,
                String authType) throws CertificateException {
            // Oh, I am easy!
        }

        public void checkServerTrusted(
                X509Certificate[] chain,
                String authType) throws CertificateException {
            // Oh, I am easy!
        }

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

    };

    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[] {easyTrustManager};

    // Install the all-trusting trust manager
    try {
        SSLContext sc = SSLContext.getInstance("TLS");

        sc.init(null, trustAllCerts, new java.security.SecureRandom());

        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

    } catch (Exception e) {
            e.printStackTrace();
    }
}

这些更改效果很好,但我不想信任每台服务器.我想使用我的密钥库文件来验证连接并以正确的方式使用 SSL.我在互联网上阅读了很多并做了很多测试,但我不明白我必须做什么以及如何去做.

Those changes worked very good, but I don´t want to Trust every server. I want to use my keystore file to validate the connection and use SSL in the right way. I read a lot on the internet and made a lot of tests, but I can´t understand what I have to do and how to do it.

有人可以帮我吗?

非常感谢

抱歉我的英语不好

-------------------------更新 2011/08/24-------------------------------------------------

-------------------------UPDATE 2011/08/24-------------------------------------------------

嗯,我还在研究这个.我做了一个新的方法来设置 KeyStore、InputStream 等

Well, I'm still working on this. I made a new method to set the KeyStore, InputStream, etc

方法如下:

private static void trustIFNetServer() {

    try {
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

        KeyStore ks = KeyStore.getInstance("BKS");

        InputStream in = context.getResources().openRawResource(R.raw.mykeystore);

        String keyPassword = "password"; 

        ks.load(in, keyPassword.toCharArray());

        in.close();

        tmf.init(ks);

        TrustManager[] tms = tmf.getTrustManagers();    

        SSLContext sc = SSLContext.getInstance("TLS");

    sc.init(null, tms, new java.security.SecureRandom());

    } catch (Exception e) {
    e.printStackTrace();
    }
}

起初我在密钥和证书方面遇到了很多问题,但现在它正在工作(我认为是这样)

First I had a lot of problems with the Key and the Certificate, but now it is working (I think so)

我现在的问题是超时异常.我不知道它为什么会生成.我认为是数据写入的问题,但我还无法解决.

My problem right now is a TimeOut Exception. I don´t know why it is generated. I'm think it's something with the data write, but I can't solve yet.

有什么想法吗?

推荐答案

您需要为您的自签名证书创建一个信任存储文件,如此处.在客户端使用它来连接您的服务器.如果您使用 JKS 或其他格式并不重要,我现在假设 JKS.

You need to create a trust store file for your self-signed certificate as described here. Use it on the client side to connect with your server. It doesn't really matter if you use JKS or another format, I'll assume JKS for now.

显然,要实现您的想法,您需要一个不同的 TrustManager.您可以使用 TrustManagerFactory 并通过新创建的信任存储提供其信任设置.

To accomplish what you have in mind you need a different TrustManager, obviously. You can use TrustManagerFactory and feed its trust settings with your newly created trust store.

TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream in = new FileInputStream("<path to your key store>");
ks.load(in, "password".toCharArray());
in.close();
tmf.init(ks);
TrustManager[] tms = tmf.getTrustManagers();

使用 tms 来初始化您的 SSLContext 而不是用于 SSL/TLS 连接的新信任设置.

Use tms to init your SSLContextinstead for the new trust settings to be used for your SSL/TLS connection.

此外,您还应确保服务器 TLS 证书的 CN 部分与服务器的 FQDN(完全限定域名)相同,例如如果您的服务器基本 URL 是https://www.example.com",则 CN证书的 应该是www.example.com".这是主机名验证所必需的,该功能可防止中间人攻击.您可以禁用此功能,但只有在使用此功能时,您的连接才会真正安全.

Also you should make sure that the CN part of the server TLS certificate is equal to the FQDN (fully qualified domain name) of your server, e.g. if your server base URL is 'https://www.example.com', then the CN of the certificate should be 'www.example.com'. This is needed for host name verification, a feature that prevents man-in-the-middle-attacks. You could disable this, but only when using this your connection will be really secure.

这篇关于Android:使用 HttpsURLConnection 的 HTTPS (SSL) 连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆