2011-08-28 210 views
10

我正尝试使用安全套接字层(HTTPS)与Java中的PHP脚本建立连接,但我已经发现为确保最大的安全性/有效性,我必须导入SSL证书我的网站用于我的应用程序...我不知道该怎么做。Java和SSL证书

如果有帮助,我的SSL证书不是自签名的,而是由StartSSL提供的,我正在使用Eclipse IDE。

有人能指出我正确的方向吗?即我需要什么文件,我应该在哪里导入它们,以及在Java中需要什么代码等等?

+0

如果它在没有导入任何证书的情况下工作,我不会看到如何确保/增加安全性通过导入网站证书。如果必须导入任何证书,则它是StartSSL的根证书,但不是您的网站证书,因为Java无法将StartSSL识别为有效的证书颁发机构。 –

+0

@JB哦。这只是因为在我之前的问题中,chubbard说我应该确保在我的客户端验证服务器的证书,以确保我正在与虚假服务对话,并提到了有关keytool的一些信息。因此,如果您说导入网站证书不影响安全性,为什么有人会导入SSL证书? – Andy

+1

这是Java的SSL堆栈,它将验证网站证书,就像浏览器一样。您在访问之前是否导入了您访问的所有SSL网站的证书?不是。浏览器验证其证书,因为它通过浏览器知道的知名证书颁发机构的认证。 StartSSL是您的案例中的证书颁发机构。 Java做同样的事情。您可能需要导入StartSSL的证书,但不需要导入网站证书。 –

回答

24

我发现,要保证最大信号的安全性/有效性我要导入我的网站使用SSL证书到我的应用程序

你是正确的部分,当你作出这样的声明。您不需要导入您的SSL证书。导入StartSSL CA证书就足够了。

此外,没有将证书导入到Java应用程序中。 Java中的SSL支持依赖于密钥库和信任库的概念,而不是在应用程序中打包的某些证书​​上。如果您要发布应用程序以供最终用户下载和执行,则不需要在应用程序中发布您的证书或私钥。私钥和相关证书将存储在密钥库中,只有您可以访问。

您的应用程序的最终用户将依赖于Java运行时的SSL支持,这将允许应用程序在验证服务器证书后建立到站点的SSL连接。 Java运行时会在信任库中附带一组默认的CA证书,并且SSL连接成功建立的唯一先决条件是服务器的SSL证书由信任库中的一个CA颁发。 startssl如果的证书不存在于Java运行时的信任,至少为6个版本,因此:

  • 你可以指导你的最终用户执行导入startssl如果CA证书的活动到Java信任库中。可能有帮助的链接包括this StartSSL forum thread(仅需要将前面4个步骤导入CA信任库到信任库),a GitHub projectthis blog post;一个免责声明 - 我没有尝试使用任何这些,你应该使用它,风险自负。
  • 或者,你可以使用-Djavax.net.ssl.trustStore=<path_to_truststore> -Djavax.net.ssl.trustStorePassword=<truststore_password> JVM启动标志用自己的信任初始化应用程序,或初始化SSL连接之前执行以下代码:

    System.setProperty("javax.net.ssl.trustStore","<path_to_truststore>"); 
    System.setProperty("javax.net.ssl.trustStorePassword","<truststore_password>"); 
    

    这是唯一的,如果你的应用程序是一个可行的方法Java SE应用程序不会碰巧是一个小程序(或者对指定信任库的方式有类似限制的应用程序)。


这也将有助于阅读了Java keytool documentation

+0

谢谢您提供的信息丰富且“富有洞察力”的答案!基本上你在说什么,是我应该只需要导入StartSSL的CA证书,然后我应该安全下去?如果我是正确的,那么您提供的链接仅适用于最终用户,并且证书不会与我的软件一起分发,但第二项要点中的方法意味着StartSSL的CA证书将始终存在,并且我的最终用户不需要做任何事情?因为我不想让我的客户必须导入StartSSL的CA证书...... – Andy

+0

CA证书有多种用途;对于像Tomcat这样的可以通过HTTPS为站点提供站点证书的Java服务器,您需要拥有带站点证书的密钥库,以及带有StartSSL CA证书的*信任库。 SSL客户端(如浏览器或Java应用程序)只需在信任库中拥有StartSSL CA证书(或任何用于验证信任的证书)。因此,您的最终用户必须将CA证书导入到cacerts文件中,并且该应用程序所建立的连接将是安全的。 –

+0

......我不知道它是否有所作为,但我计划使用launch4j将JRE与我的应用程序一起分发,这样我就不必依赖我的客户安装了Java。那么,这是否意味着StartSSL的CA证书也可以与JRE一起打包? – Andy

0

看看下面的文章:http://stilius.net/java/java_ssl.php 它包含代码示例,这可能有助于在您尝试从代码访问您的脚本的情况下。

需要注意的是,你要么应该使用系统属性

javax.net.ssl.keyStore 
javax.net.ssl.keyStorePassword 

使用keytool工具SSL证书传递到JVM或将其导入到JRE密钥库

+0

谢谢你的回答@Sergey。不幸的是,我已经看过你建议的文章。如果我再研究一下它可能会有所帮助,但这对我来说是一个全新的主题,所以我有时会面临一些压力,所以我讨厌这么说,但我一直在寻找最简单的方法。幸运的是,我发现了与Vineet讨论的最佳方式,但是非常感谢! – Andy

0

我发现,要保证最大信号安全/有效期我必须 导入SSL证书

不,你没有。如果您的客户尚未信任服务器证书的签署人,则只需要执行此步骤,这仅在服务器证书是自签名或签名的情况下才会产生。由内部CA.

+0

谢谢你的回答。不过,不幸的是,我已经导入了一个证书 - 但我不认为现在有必要,但是我怎么知道我的客户是否不信任服务器证书的签名者:我会收到一个例外应用时使用'Htttpsurlconnection'? – Andy

+0

@你会得到同样的例外,你在第一个地方。我的代码中的 – EJP

1

以下方法加载默认(cacerts)密钥库,检查是否安装了证书,如果没有,则安装它。它消除了在任何服务器上手动运行keystore命令的需要。

它假设默认密钥库密码(changeit)未更改,如果不是,则更新CACERTS_PASSWORD。请注意,该方法在添加证书后保存密钥库,因此在证书永久存储在商店后运行后。

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.security.KeyStore; 
import java.security.KeyStoreException; 
import java.security.NoSuchAlgorithmException; 
import java.security.cert.Certificate; 
import java.security.cert.CertificateException; 
import java.security.cert.CertificateFactory; 

/** 
* Add a certificate to the cacerts keystore if it's not already included 
*/ 
public class SslUtil { 
    private static final String CACERTS_PATH = "/lib/security/cacerts"; 

    // NOTE: DO NOT STORE PASSWORDS IN PLAIN TEXT CODE, LOAD AT RUNTIME FROM A SECURE CONFIG 
    // DEFAULT CACERTS PASSWORD IS PROVIDED HERE AS A QUICK, NOT-FOR-PRODUCTION WORKING EXAMPLE 
    // ALSO, CHANGE THE DEFAULT CACERTS PASSWORD, AS IT IMPLORES YOU TO! 
    private static final String CACERTS_PASSWORD = "changeit"; 

    /** 
    * Add a certificate to the cacerts keystore if it's not already included 
    * 
    * @param alias The alias for the certificate, if added 
    * @param certInputStream The certificate input stream 
    * @throws KeyStoreException 
    * @throws NoSuchAlgorithmException 
    * @throws CertificateException 
    * @throws IOException 
    */ 
    public static void ensureSslCertIsInKeystore(String alias, InputStream certInputStream) 
      throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException{ 
     //get default cacerts file 
     final File cacertsFile = new File(System.getProperty("java.home") + CACERTS_PATH); 
     if (!cacertsFile.exists()) { 
      throw new FileNotFoundException(cacertsFile.getAbsolutePath()); 
     } 

     //load cacerts keystore 
     FileInputStream cacertsIs = new FileInputStream(cacertsFile); 
     final KeyStore cacerts = KeyStore.getInstance(KeyStore.getDefaultType()); 
     cacerts.load(cacertsIs, CACERTS_PASSWORD.toCharArray()); 
     cacertsIs.close(); 

     //load certificate from input stream 
     final CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
     final Certificate cert = cf.generateCertificate(certInputStream); 
     certInputStream.close(); 

     //check if cacerts contains the certificate 
     if (cacerts.getCertificateAlias(cert) == null) { 
      //cacerts doesn't contain the certificate, add it 
      cacerts.setCertificateEntry(alias, cert); 
      //write the updated cacerts keystore 
      FileOutputStream cacertsOs = new FileOutputStream(cacertsFile); 
      cacerts.store(cacertsOs, CACERTS_PASSWORD.toCharArray()); 
      cacertsOs.close(); 
     } 
    } 
} 

使用它,像这样:

SslUtil.ensureSslCertIsInKeystore("startssl", new FileInputStream("/path/to/cert.crt")); 
+0

这导致java.io.FileNotFoundException:C:\ Program Files文件(x86)\ Java \ jre1.8.0_45 \ lib \ security \ cacerts(访问被拒绝)我将证书下载到临时文件夹,然后用一个唯一的别名(不是starttls)和fileInputStream导入它。我的证书来自HTTPS服务器(www.gmx.at) – lumo

+0

谢谢!这篇文章帮助我阅读一个密钥库。 – rray

+0

问题,在代码中以纯文本形式存储密码不是一个相当大的安全漏洞吗?或者,当涉及SSL连接时,这并不重要吗? – Flaom

2

显然,由于某种原因,mailgun工程师不希望给我们如何解决这个明确的指示。这就是我所做的

我们运行tomcat8并通过球衣web服务连接到mailgun API。我遵循这个用户指示,它工作正常。希望这可以帮助某人。

1/22,由于赛门铁克的PKI基础设施设置为不可信,我们更新了SSL证书。某些旧版本的Java没有“DigiCert Global Root G2”CA.

有几种选择:

导入 “DigiCert全局根G2” CA到您 “的cacerts” 文件。 将您的JRE升级到8u91(或更高版本),其中包含此根目录。 要导入“DigiCert Global Root G2”您可以从https://www.digicert.com/digicert-root-certificates.htm下载根目录。确保您正在下载正确的根证书。

一旦证书下载后,您需要将它与类似如下的命令导入:

的keytool -import -keystore -trustcacerts /路径/到/ cacerts的-storepass的changeit -noprompt -alias digicert -global-root -g2 -file /path/to/digicert.crt 您需要设置Java密钥库的路径以及下载的根证书的位置。


所以 1. /path/to/digicert.crt是您刚刚下载的文件。 2。/ path/to/cacerts - 这是你的JRE路径。我找到/ -name cacerts -print“这将帮助您快速找到文件系统上的所有java cacerts。对我来说,它是/ usr/lib/jvm/java-7 -openjdk-amd64/jre/lib/security/cacerts