关于通过HTTPS SSL正确发布的澄清(/ TLS?)

时间:2018-04-24 14:51:12

标签: java ssl-certificate httpsurlconnection

SSL的新手总数。我知道我应该使用HTTPS SSL(/ TLS?)从我的客户端应用程序将数据发送到我的服务器。或者至少那是我想做的事。

我以前在Java中的实现使用了HttpURLConnection,看起来像这样:

    HttpURLConnection conn = null;

    try
    {
        URL url = new URL(urlString);
        conn = (HttpURLConnection) url.openConnection();
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        OutputStream os = conn.getOutputStream();
        OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
        osw.write(dataString);
        osw.flush();
        osw.close();
        os.close();
        conn.connect();

        if(conn.getResponseCode() != 200)
            throw new MyServerException();

        BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
        String output;
        StringBuilder sb = new StringBuilder();

        while ((output = br.readLine()) != null) {
            sb.append(output);
        }

        if(conn != null)
            conn.disconnect();

        return sb.toString();
    }
    catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    catch (ProtocolException e) {
        e.printStackTrace();
    }
    catch (MalformedURLException e) {
        e.printStackTrace();
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    finally {
        if(conn != null)
            conn.disconnect();
    }

    throw new MyServerException();

......这很好用。我发现this web page哪种情况表明我需要做的就是将HttpURLConnection切换为HttpsURLConnection,一切都应该正常。

另一方面,在我的服务器的cPanel上,我找到了一个Lets Encrypt部分,它使我可以将证书应用到我的服务器域。

除此之外,还设置了PEM-Encoded CertificatePEM-Encoded Issuer证书。

但后来我有点难过。我是否只是假设上面的代码更新为使用HttpsURLConnection有效?我怎么知道它的工作原理。例如,如果我从我的cPanel中删除已颁发的证书,那么上面的代码仍然有用......

自发布以来我发现的事情

如果我将urlString设为http它会引发异常,而如果它是https地址则不然,那么我猜是好的

此外,这this post表明我正走在正确的轨道上,因为我没有按照那里的建议得到任何错误,并且没有人提到这种做法是错误的。

Of possible interest,它实际上指出" SSL现在称为传输层安全性(TLS),"这已经简化了事情。

This looks like a great文章。我还注意到,除了Lets Encrypt选项之外,我们还必须在cPanel上设置SSL / TLS。真有意义,最初没有看到。 更多关闭Lets Encrypt是一项免费服务,可为您提供自动使用的证书,而不是从服务提供商处购买。但是,您也可以签署自己的免费证书,但不能识别"由任何受信任的证书颁发机构(CA)。

2 个答案:

答案 0 :(得分:1)

我通常使用像https url连接这样的方法信任任何证书,如下所示。

try {
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, new X509TrustManager[]{new X509TrustManager() {
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
    }}, new SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
} catch(NoSuchAlgorithmException e) {
    e.printStackTrace();
} catch(KeyManagementException e) {
    e.printStackTrace();
}

使用没有主机名的证书向服务器发出安全请求。

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

然后,您可以将HttpURLConnection对象作为HttpsURLConnection对象获取。

HttpURLConnection connection = null;
try
{
    URL _url = new URL(url);
    String scheme = _url.getProtocol();

    if(scheme.equals("https")) {
       connection = (HttpsURLConnection)new URL(url).openConnection();
    }
 }catch(...){} 

答案 1 :(得分:0)

好的,我终于在一整天后彻底解决了这个问题。 Firslty SSL和TLS通常意味着同样的想法,TLS是旧SSL的替代品。接下来,要获得安全连接,您需要在服务器上安装证书。这实际上很容易通过cPanel。事实上,我建议使用Lets Encrypt,它提供持续90天的免费证书。您可以通过设置crontab作业自动续订证书服务器端,这样它们不仅是免费的,而且也是永久性的。

设置证书后,您可以使用以下代码建立安全连接和POST:

    SSLContext sc = null;
    HttpsURLConnection conn = null;

    try {
        URL httpsURL = new URL(urlString);
        sc = SSLContext.getInstance("TLSv1.2");
        sc.init(null, null, new java.security.SecureRandom());
        conn  = (HttpsURLConnection) httpsURL.openConnection();
        conn.setSSLSocketFactory(sc.getSocketFactory());

        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        OutputStream os = conn.getOutputStream();
        OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
        osw.write(dataString);
        osw.flush();
        osw.close();
        os.close();
        conn.connect();

        if(conn.getResponseCode() != 200)
            throw new MyServerException();

        BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
        String output;
        StringBuilder sb = new StringBuilder();

        while ((output = br.readLine()) != null) {
            sb.append(output);
        }

        if(conn != null)
            conn.disconnect();

        return sb.toString();
    }
    catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    catch (KeyManagementException e) {
        e.printStackTrace();
    }
    catch (MalformedURLException e) {
        e.printStackTrace();
    }
    catch (IOException e) {
        e.printStackTrace();
    }

    if(conn != null)
        conn.disconnect();

    throw new MyServerException();

真的很好,很容易。也许我还需要某种主机名验证器,比如@tommybee在他的回答中提到的。