尝试通过Studio中的android应用通过https连接到服务器时未验证主机名

时间:2018-07-30 14:09:44

标签: android-studio https

我想我已经明白了(请告诉我这是否会留下明显的安全漏洞,但是要轻柔;-)

我认为我在这里将自己拥有的钥匙与房东的钥匙进行比较:

return Arrays.equals(bytes, encodedKey);

我认为这对于我想做的事情应该已经足够了。我还想确认来回传递用户名/密码等时,所有流量都将被加密。

    private HttpsURLConnection getTrustedConnection()
        throws CertificateException, KeyStoreException,  NoSuchAlgorithmException,
        KeyManagementException, IOException {

    Certificate certificate;
    String keyStoreType;
    final KeyStore keyStore;
    String tmfAlgorithm;
    TrustManagerFactory trustManagerFactory;
    final byte[] encodedKey;
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    InputStream inputStream = myContext.getResources().openRawResource(
            myContext.getResources().getIdentifier("server_crt", "raw",
                    myContext.getPackageName()));
    BufferedInputStream caInput = new BufferedInputStream(inputStream);
    certificate = certificateFactory.generateCertificate(caInput);
    encodedKey = certificate.getEncoded();

    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
        @Override
        public boolean verify(String hostName, SSLSession sslSession) {
            X509Certificate[] peerCertificateChain;
            try {
                peerCertificateChain = sslSession.getPeerCertificateChain();
                String host = sslSession.getPeerHost();
                byte[] bytes = peerCertificateChain[0].getEncoded();
                return Arrays.equals(bytes, encodedKey);
            } catch (SSLPeerUnverifiedException | CertificateEncodingException e) {
                e.printStackTrace();
            }
            return false;
        }
    });

    caInput.close();
    keyStoreType = KeyStore.getDefaultType();
    keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", certificate);
    tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    trustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm);
    trustManagerFactory.init(keyStore);
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
    URL url = new URL(String.format(myContext.getString(R.string.command_url), myHost,
            myPort, myCommand));

    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
    connection.setSSLSocketFactory(sslContext.getSocketFactory());
    connection.setReadTimeout(10000);
    connection.setConnectTimeout(10000);
    connection.setRequestMethod("POST");
    connection.setRequestProperty("User-Agent", "Mozilla/5.0");
    connection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
    connection.setRequestProperty("Content-Type", "application/json");
    connection.setDoInput(true);
    connection.setDoOutput(true);
    return connection;
}

public void run() {
    HttpsURLConnection connection = null;

    try {
        connection = getTrustedConnection();
        OutputStreamWriter wr= new OutputStreamWriter(connection.getOutputStream());
        wr.write(myParameters.toString());
        wr.flush();
        wr.close();

        switch (connection.getResponseCode()) {
           case HttpURLConnection.HTTP_CREATED:
           case HttpURLConnection.HTTP_OK:
               BufferedReader bufferedReader = new BufferedReader(
                       new InputStreamReader(connection.getInputStream()));
               StringBuilder stringBuilder = new StringBuilder();
               String line;
               while ((line = bufferedReader.readLine()) != null) {
                   stringBuilder.append(line);
               }
               bufferedReader.close();
               JSONObject jsonObj = new JSONObject(stringBuilder.toString());
               myParent.done(jsonObj);
               break;
           default:
               myParent.done(null);
        }
    } catch (Exception e) {
        JSONObject json = new JSONObject();
        try {
            json.put(INVALID_LOGIN, e.getMessage());
        } catch (JSONException e1) { System.out.println(e1.getMessage());
        }
        myParent.done(json);
    } finally {
        if (connection != null) {
            connection.disconnect();
        }
    }
}

如果通过主机名连接到服务器(在与Android Studio中的服务器模拟同一台计算机上的Android手机时),以下代码将非常有效:

private HttpsURLConnection getTrustedConnection()
        throws CertificateException, KeyStoreException,  NoSuchAlgorithmException,
        KeyManagementException, IOException {

    Certificate ca;
    String keyStoreType;
    KeyStore keyStore;
    String tmfAlgorithm;
    TrustManagerFactory trustManagerFactory;

    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    InputStream ins = myContext.getResources().openRawResource(
            myContext.getResources().getIdentifier("server_crt", "raw",
                    myContext.getPackageName()));
    BufferedInputStream caInput = new BufferedInputStream(ins);
    ca = cf.generateCertificate(caInput);
    caInput.close();
    keyStoreType = KeyStore.getDefaultType();
    keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);
    tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    trustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm);
    trustManagerFactory.init(keyStore);
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
    URL url = new URL(String.format(myContext.getString(R.string.command_url), myHost,
            myPort, myCommand));

    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
    connection.setSSLSocketFactory(sslContext.getSocketFactory());
    connection.setReadTimeout(10000);
    connection.setConnectTimeout(10000);
    connection.setRequestMethod("POST");
    connection.setRequestProperty("User-Agent", "Mozilla/5.0");
    connection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
    connection.setRequestProperty("Content-Type", "application/json");
    connection.setDoInput(true);
    connection.setDoOutput(true);
    return connection;
}

并这样称呼它:

httpsURLConnection connection = null;
connection = getTrustedConnection();
OutputStreamWriter wr= new OutputStreamWriter(connection.getOutputStream());
wr.write(myParameters.toString());
wr.flush();
wr.close();
// do stuff

但是我的问题是我无法通过android物理设备上的主机名进行连接(此外,一旦一切正常,我将把目的地更改为动态的家庭IP地址。我确实想保持类似尽可能(如果可以的话)确保安全,因此我正在尝试执行以下操作:

public HttpsURLConnection getSomewhatSecureConnection()
        throws NoSuchAlgorithmException, KeyManagementException, IOException {
    TrustManager[] trustAllCerts = new TrustManager[] {
            new X509TrustManager() {

                @Override
                public void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException {
                    // not implemented
                }

                @Override
                public void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException {
                    // not implemented
                }

                @Override
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

            }
    };

    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
        @Override
        public boolean verify(String s, SSLSession sslSession) {
            return true;
        }
    });

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

    URL url = new URL(String.format(myContext.getString(R.string.command_url), myHost, myPort,
            myCommand));
    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
    return connection;
}

我用同样的方式称呼它:

connection = getSomewhatSecureConnection();
OutputStreamWriter wr= new OutputStreamWriter(connection.getOutputStream());
wr.write(myParameters.toString());
wr.flush();
wr.close();
//do stuff

我计划在HostnameVerifier或TrustManager中添加一些代码以对证书进行一些检查,但是现在我受困了。我要么得到

java.net.ProtocolException: method does not support a request body: GET

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

    OutputStreamWriter wr= new OutputStreamWriter(connection.getOutputStream());

取决于我是否放置

HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();

在SSLContext初始化代码之前或之后。

0 个答案:

没有答案