安卓:使用HTTPS(SSL)连接HttpsURLConnectionHTTPS、SSL、HttpsURLConnection

2023-09-03 21:07:21 作者:渡你眉间河川

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

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

我用的HttpURLConnection双方之间发送和recibe XMLS。

I were using HttpURLConnection to send and recibe XMLs between both.

code:

    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来发送XMLS的安全性。

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。 我readed了很多在互联网上,使大量的测试,但我不能明白我必须做和怎么做。

Those changes worked very good, but I don´t want to Trust every server. I want to use mi keystore file to validate the conection and use SSL in the right way. I readed a lot on internet and making a lot of test, but i can´t understand what i have to do and how to do.

有人可以帮我吗?

非常感谢你。

对不起,我的英文不好

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

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

嗯,我仍然在做这个。我提出一个新的方法来设置日密钥存储的InputStream等

well, i'm still working on this. I make a new method to set de 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 is working (i think so)

我的问题,现在是一个超时异常。我不知道这是为什么产生。我认为这是一些与数据写的,但我不能解决呢。

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

你知道吗?

推荐答案

您需要为您的自签名证书信任存储文件中所描述的here第一,使用它在客户端与服务器的连接。它如果使用JKS或其他形式其实并不重要,我会认为JKS现在。

You need to create a trust store file for your self-signed certificate as described here first and 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 来初始化你的的SSL连接来代替用于您的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。这是需要主机名验证功能,该功能$人在最中间的攻击p $ pvents。您可以禁用此功能,但使用这您的连接,只有当才会真正安全。

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.