如何通过Web服务制作“简单SSL”?

5
我知道如何使用证书保护Web服务。以下是我的客户端代码:

我知道如何使用证书保护Web服务。以下是我的客户端代码:

  SSLContext ssl = SSLContext.getInstance("SSLv3");
  KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
  KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
  String password = Configuration.getConfig("keyStorePassword");
  store.load(new FileInputStream(new File(Configuration.getConfig("keyStore"))), password.toCharArray());
  kmf.init(store, password.toCharArray());
  KeyManager[] keyManagers = new KeyManager[1];
  keyManagers = kmf.getKeyManagers();
  TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
  tmf.init(store);
  TrustManager[] trustManagers = tmf.getTrustManagers();
  ssl.init(keyManagers, trustManagers, new SecureRandom());

  HttpsConfigurator configurator = new HttpsConfigurator(ssl);
  Integer port = Integer.parseInt(Configuration.getConfig("port"));
  HttpsServer httpsServer = HttpsServer.create(new InetSocketAddress(Configuration.getConfig("host"), port), 0);
  httpsServer.setHttpsConfigurator(configurator);

  Implementor implementor = new Implementor(); // class with @WebService etc.
  HttpContext context = (HttpContext) httpsServer.createContext("/EventWebService");
  Endpoint endpoint = Endpoint.create( implementor );
  endpoint.publish(context);

现在,如何制作“简单的SSL”?如何在不在客户端存储证书的情况下建立SSL连接(就像通过浏览器连接HTTPS一样)?
5个回答

5
Java Runtime Environment 中的 cacerts 文件已经包含了大量(最常用的)证书颁发机构。如果你所使用的证书是由其中一个根 CA 签名的,那么你就不需要担心与客户共享任何证书的问题。
然而,如果你使用的是自签名证书,并且不想在信任库中传递/导入证书,则可以实现自定义 X509TrustManager 并为你的连接创建自定义 SSLContext。更多详细信息请参阅此博客
自签名证书对于开发和测试环境非常有用,但你真的应该考虑从认可的证书颁发机构(如 Verisign、Thwate 等)获取你的服务器证书签名。

我认为TrustAlmostEverythingManager就是我正在寻找的东西。 我正在使用精确的IP连接到服务器(因此没有可能被欺骗)。我只想保护连接免受窃听。我的想法正确吗?也许将来需要生成客户端和服务器证书。 - razor
啊...是的,但如果您的Web服务消费者在组织之外,他们很难信任自签名证书。我建议提前花费一些钱让您的客户感觉更好。我还建议获取一个适当的域名,而不是使用其中包含IP地址的WSDL进行共享。自签名证书非常适用于内部应用程序和测试环境,但对于外部客户来说,多花一点钱会有很大的帮助! - helios
客户在组织外部,为什么难以信任?你的意思是很难验证服务器吗? 我知道来自CA的证书会更好,这个环境的管理员也知道。 现在,这不仅取决于我。也许将来会有适当的证书(由CA颁发)等。 - razor
是的 - 我并不是说技术上会更加困难。只是对于某些人来说,很难相信一个使用自签名证书的网站,特别是当网站服务数据交换涉及敏感信息时。但我感觉你已经意识到了后果,所以不用担心 :-) - helios

2
您可以通过以下方式控制https服务器是否需要客户端证书:
HttpsConfigurator cfg = new HttpsConfigurator(sslCtx){
  public void configure(HttpsParameters params) {
        SSLParameters sslparams = getSSLContext().getDefaultSSLParameters();

        // Modify the default params:
        // Using this, server will require client certs
        //sslparams.setNeedClientAuth(true);

        // Using this, server will request client certs. But if not available,
        // it will continue anyway.
        sslparams.setWantClientAuth(true);

        params.setSSLParameters(sslparams);
  }
};
HttpsServer httpsS = HttpsServer.create(new InetSocketAddress(8081), 50);
httpsS.setHttpsConfigurator(cfg);

如果不需要客户端证书,客户端可以没有证书连接,所以简单的调用https就可以工作。
在我的博客中,您可以看到一个客户端的示例,如何绕过服务器证书和主机名验证(虽然不建议使用,但对于测试非常有用)。 http://jakubneubauer.wordpress.com/2011/09/06/java-webservice-over-ssl/

2
如果我理解你的意思正确,那么你希望只有服务器端身份验证,就像在浏览器中连接https站点一样,而不需要客户端管理任何证书。
您的客户端将像往常一样连接,只需在连接URL中用https替换http。 Java以的形式管理自己的“默认可信根CA机构”集,这是位于$JRE HOME/lib/security中的JKS密钥库文件。如果您从任何CA购买证书,其发行证书的根在cacerts中包含的证书之一中,则客户端证书验证将自动成功。搜索“SSL/TLS服务器证书”,您会找到合适的供应商。
另一方面,如果您使用自签名的证书,则没有办法使客户端上的证书验证成功,除非在客户端的证书信任存储中导入您自制的证书。但这就是为什么“真正的”SSL/TLS证书需要花费金钱,而您的自签名证书不需要-任何人都可以生成他们自己的自制证书,但信任它们是完全不同的故事。

0

只需使用HTTPS建立连接即可。只要客户端使用标准的受信任证书,它就可以正常工作。如果他们有自签名证书,则需要将证书导入Java密钥库。


我想创建安全的Web服务,但我不想在客户端机器上安装任何证书。我希望像浏览器通过HTTPS连接服务器一样连接到服务器。 客户端和服务器都是由我编写的,我可以进行更改。 - razor
我的意思是:简单的TLS握手http://en.wikipedia.org/wiki/Transport_Layer_Security - razor
浏览器和Java密钥库都预装了公共受信任的证书。它们不会动态协商...否则它们将不被信任。 - ryber

0

浏览器中的HTTPS之所以能够工作,是因为客户端上有一个包含SSL证书的信任库。换句话说:客户端上存储了证书。

如果您想在没有存储在客户端上的任何证书的情况下使用HTTPS,我认为您应该查看this article,该文章解释了如何关闭HTTPS连接上的默认证书验证。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接