标签:安全 https tomcat httpsurlconnection sslsocket
在前面所讲到的一些安全技术手段如:消息摘要、加解密算法、数字签名和数据证书等,一般都不会由开发者直接地去使用,而是经过了一定的封装,甚至形成了某些安全协议,再暴露出一定的接口来供开发者使用。因为直接使用这些安全手段,对开发者的学习成本太高,需要深入了解底层实现才行,而直接使用封装后暴露出来的接口就容易多了。一、Tomcat中HTTPS协议的配置
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="true" sslProtocol="TLS" keystoreFile="conf/serverKeyStore.jks" keystorePass="gitblit" truststoreFile="conf/caKeyStore.p12" truststorePass="gitblit" truststoreType="pkcs12"/>
package com.xtayfjpk.security.jsse; import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; import java.security.KeyStore; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; import org.junit.Test; public class SSLSocketTest { @Test public void testRunServer() throws Exception { //获取SSL上下文 SSLContext context = SSLContext.getInstance("SSL"); String keyStorePassword = "password"; //获取服务端KeyStore KeyStore serverKeys = getKeyStore("serverKeys", "jks", keyStorePassword); //获取KeyManagerFactory KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); String privateKeyPassword = "password"; //初始化KeyManagerFactory keyManagerFactory.init(serverKeys, privateKeyPassword.toCharArray()); //获取TrustManagerFactory TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); String trustStorePassword = "password"; //获取服务端信任KeyStore KeyStore serverTrustKeys = getKeyStore("serverTrust", "jks", trustStorePassword); //初始化TrustManagerFactory trustManagerFactory.init(serverTrustKeys); //初始化SSL上下文 context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); //使用SSL上下文获取SSLServerSocketFactory SSLServerSocketFactory ssf = (SSLServerSocketFactory) context.getServerSocketFactory(); //使用SSLServerSocketFactory创建出SSLServerSocket,并监听指定端口 SSLServerSocket serverSocket = (SSLServerSocket) ssf.createServerSocket(9999); //设置需要对客户端进行认证 serverSocket.setNeedClientAuth(true); while(true) { try { //等待客户端连接 SSLSocket socket = (SSLSocket) serverSocket.accept(); InputStream in = socket.getInputStream(); byte[] buf = new byte[1024]; int len = in.read(buf); System.out.println(new String(buf, 0, len)); in.close(); } catch (Exception e) { e.printStackTrace(); } } } @Test public void testRunClient() throws Exception { SSLContext context = SSLContext.getInstance("SSL"); String keyStorePassword = "password"; KeyStore clientKeys = SimpleSSLServer.getKeyStore("clientKeys", "jks", keyStorePassword); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); String privateKeyPassword = "xtayfjpk"; keyManagerFactory.init(clientKeys, privateKeyPassword.toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); String trustStorePassword = "password"; KeyStore serverTrustKeys = getKeyStore("clientTrust", "jks", trustStorePassword); trustManagerFactory.init(serverTrustKeys); context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); //使用SSL上下文创建SSLSocket SSLSocketFactory factory = (SSLSocketFactory) context.getSocketFactory(); String host = "127.0.0.1"; //创建SSLSocket SSLSocket socket = (SSLSocket) factory.createSocket(host, 9999); //与服务端进行通信 OutputStream outputStream = socket.getOutputStream(); outputStream.write("xtayfjpk".getBytes()); outputStream.flush(); outputStream.close(); socket.close(); } public static KeyStore getKeyStore(String keyStorePath, String type, String keyStorePassword) throws Exception { KeyStore keyStore = KeyStore.getInstance(type); FileInputStream in = new FileInputStream(keyStorePath); keyStore.load(in, keyStorePassword.toCharArray()); in.close(); return keyStore; } }
package com.xtayfjpk.security.jsse; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.security.KeyStore; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; import org.junit.Test; public class HttpsUrlConnectionTest { @Test public void test() throws Exception { URL url = new URL("https://localhost:8443/"); HttpsURLConnection connection = HttpsURLConnection.class.cast(url.openConnection()); SSLContext context = SSLContext.getInstance("SSL"); String keyStorePassword = "gitblit"; KeyStore clientKeys = SimpleSSLServer.getKeyStore("D:\\java-app\\apache-tomcat-6.0.35\\conf\\clientKeyStore.p12", "pkcs12", keyStorePassword); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); String privateKeyPassword = "gitblit"; keyManagerFactory.init(clientKeys, privateKeyPassword.toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); String trustStorePassword = "gitblit"; KeyStore serverTrustKeys = getKeyStore("D:\\java-app\\apache-tomcat-6.0.35\\conf\\clientTrustStore.jks", "jks", trustStorePassword); trustManagerFactory.init(serverTrustKeys); context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); //使用SSL上下文创建SSLSocket SSLSocketFactory factory = (SSLSocketFactory) context.getSocketFactory(); //如果服务端没设置需要认证客户端的话,可以不用设置SSLSocketFactory connection.setSSLSocketFactory(factory); connection.setDoInput(true); connection.setDoOutput(true); InputStream in = connection.getInputStream(); String line = null; BufferedReader reader = new BufferedReader(new InputStreamReader(in)); while((line=reader.readLine())!=null) { System.out.println(line); } } public static KeyStore getKeyStore(String keyStorePath, String type, String keyStorePassword) throws Exception { KeyStore keyStore = KeyStore.getInstance(type); FileInputStream in = new FileInputStream(keyStorePath); keyStore.load(in, keyStorePassword.toCharArray()); in.close(); return keyStore; } }
在Tomcat中HTTPS协议的配置时说到,服务器KeyStore最好只有一个条目,否则会造成所使用条目不确定的情况。但有时候你可能会想,该KeyStore中存储多个条目,在启动时通过配置条目别名来指定具体的条目,因为Tomcat中没有提供别名配置支持,所以KeyStore中最好还是只有一个条目。但如果是自己写SSLSocket程序,可能通过扩展来支持,如下:
package com.xtayfjpk.security; import java.net.Socket; import java.security.Principal; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.Arrays; import javax.net.ssl.SSLEngine; import javax.net.ssl.X509ExtendedKeyManager; import javax.net.ssl.X509KeyManager; public class MyAliasedX509ExtendKeyManager extends X509ExtendedKeyManager { private String keyAlias; private X509KeyManager keyManager; public MyAliasedX509ExtendKeyManager(String keyAlias, X509KeyManager keyManager) { this.keyAlias = keyAlias; this.keyManager = keyManager; } //提供给客户端使用,用于选择客户端Keystore中的一个别名 @Override public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) { String alias = keyAlias==null ? keyManager.chooseClientAlias(keyTypes, issuers, socket) : keyAlias; return alias; } //提供给服务端使用,用于选择服务端Keystore中的一个别名 @Override public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { String alias = keyAlias==null ? keyManager.chooseServerAlias(keyType, issuers, socket) : keyAlias; return alias; } @Override public X509Certificate[] getCertificateChain(String alias) { return keyManager.getCertificateChain(alias); } @Override public String[] getClientAliases(String keyType, Principal[] issuers) { return keyManager.getClientAliases(keyType, issuers); } @Override public PrivateKey getPrivateKey(String alias) { return keyManager.getPrivateKey(alias); } @Override public String[] getServerAliases(String keyType, Principal[] issuers) { return keyManager.getServerAliases(keyType, issuers); } @Override public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) { String alias = keyAlias==null ? super.chooseEngineClientAlias(keyType, issuers, engine) : keyAlias; return alias; } @Override public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { String alias = keyAlias==null ? super.chooseEngineServerAlias(keyType, issuers, engine) : keyAlias; return alias; } }
通过继承X509ExtendedKeyManager,自己实现一个KeyManager,别名通过构造方法传入,然后使用自己的KeyManager实现类包装KeyManagerFactory创建的KeyManager即可通过别名达到指定KeyStore中被使用条目的目的。
标签:安全 https tomcat httpsurlconnection sslsocket
原文地址:http://blog.csdn.net/xtayfjpk/article/details/46491471