Java 关于通过HTTPS SSL(/TLS?)正确发布的说明

Java 关于通过HTTPS SSL(/TLS?)正确发布的说明,java,ssl-certificate,httpsurlconnection,Java,Ssl Certificate,Httpsurlconnection,总新手到SSL。我知道我应该使用HTTPS SSL(/TLS?)将数据从客户端应用程序发送到服务器。或者至少这是我想做的 我以前的Java实现使用了HttpURLConnection,看起来像这样: HttpURLConnection conn = null; try { URL url = new URL(urlString); conn = (HttpURLConnection) url.openConnection();

总新手到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();
。。。这个很好用。我发现我需要做的就是将我的
HttpURLConnection
切换到
HttpsURLConnection
,一切都应该正常

另一方面,在我服务器的cPanel上,我发现了一个
letsnypt
部分,它使我能够将证书应用到我的服务器域

除其他事项外,设置此设置会产生
PEM编码证书
PEM编码颁发者
证书

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

发帖后我发现的事情

如果我将我的
urlString
设为
http
它会抛出异常,而如果它是
https
地址,它不会,所以我想这很好

此外,这也表明我走的是正确的道路,因为我没有得到任何错误的建议,而且没有人提到这种方式是错误的

,它实际上指出“SSL现在被称为传输层安全性(TLS)”,这已经简化了事情


文章。我还注意到,除了Lets Encrypt选项之外,我们还必须在cPanel上设置SSL/TLS。真有道理,原来没看到更多:事实证明,Lets Encrypt是一项免费服务,它为您提供自动证书供您使用,而不是从服务提供商那里购买。不过,您也可以对自己的证书进行签名,这些证书是免费的,但不会被任何受信任的证书颁发机构(CA)识别。

我通常使用如下方法使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(...){} 

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

设置证书后,可以使用以下代码建立安全连接并发布:

    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。

谢谢你的回答。这是否会在客户端和服务器之间创建安全的TLS连接?我想我明白你的意思了。例如,如果我有一个基于网络的客户端,我希望浏览器能够识别我的网页服务器是安全的(带有绿色的挂锁),那么我需要一个我实际付费的证书的唯一原因就是。但事实上,我正在处理移动和桌面应用程序,它们没有现代浏览器的警告。。。。。。所以我可以签署我自己的证书,而不必使用Lets加密或从CA购买证书?只要我有一个安全的连接,这就是最重要的。基本上,如果你有自己的http客户端,这不会有问题。我一直在使用我在android应用程序中提供的代码,但我们有一个带有公共证书的服务器。我还有一个带有我自己通过openssl生成的证书的推送客户端,它仍在工作。