Java SSL 证书细节
来源:互联网 发布:知乎周刊plus 编辑:程序博客网 时间:2024/05/17 09:12
关于SSL这块,网上很多,但很多都是讲原理或怎么生成证书实现简单通信,没有讲到实践时的诸多细节。
SSL, 即Secure Sockets Layer 安全套接层。本文介绍SSL的一些常见问题,用的语言主要是Java。
首先明确SSL的目的,就是加密。就是在Socket的基础上增加安全性。一般来讲,就是避免客户端向服务端传输数据时,被人拦截篡改,避免所谓的中间人攻击,防范钓鱼网站。
关于它的基础概念,可以看
【上】安全HTTPS-全面详解对称加密,非对称加密,数字签名,数字证书和HTTPS
【下】安全HTTPS-全面详解对称加密,非对称加密,数字签名,数字证书和HTTPS
问题1:证书生成和格式
网上搜索SSL,有很多生成证书的教程。可是会发现有的是用Java的Keytool生成的cer,有的是用openssl来生成的pem。这是为什么呢?其实这些证书本质是一样的,只是文件格式不一样。所以如果想在Java里使用pem格式的证书,就要转化。转化的方式在这个问题里已有回答:
Convert a PEM-formatted String to a java.security.cert.X509Certificate
另外,公钥和私钥分别以什么形式存在?公钥存在于证书文件中,私钥存在于Keystore文件中。注意Java里的Keystore类可以是有私钥的Keystore,也可以是只有公钥的Keystore。
还有,为什么使用Java keytool生成的证书要设置密码?这个密码是JKS文件的密码,注意不是公钥或私钥哦,是用于防范别人随便乱拿的。
问题2:既然是加密,那么可不可以脱离Socket存在?
可以。可以直接使用公钥来加密数据,再用私钥解密数据。具体方法参考:
Java加密技术(八)——数字证书
问题3:单向认证,即只确认服务端是否真实可靠的话,要做什么?以SSLSocket举例。
如果只需要信任自己生成的证书
代码:
public class TestSSLSocketClient { private static String path = "e:\\keytool\\sslclient.keystore"; private static char[] password = "aaaaaaa".toCharArray(); /** * @param args */ public static void main(String[] args) { SSLContext context = null; try { KeyStore ts = KeyStore.getInstance("JKS"); ts.load(new FileInputStream(path), password); TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ts); TrustManager [] tm = tmf.getTrustManagers(); context = SSLContext.getInstance("SSL"); context.init(null, tm, null); } catch (...... e) { //省略捕获的异常信息 e.printStackTrace(); } SSLSocketFactory ssf = context.getSocketFactory(); try { SSLSocket ss = (SSLSocket) ssf.createSocket("localhost", 8000); System.out.println("客户端就绪。"); ObjectInputStream br = new ObjectInputStream(ss.getInputStream()); try { System.out.println(br.readObject()); } catch (ClassNotFoundException e) { e.printStackTrace(); } br.close(); ss.close(); System.out.println("客户端测试ok"); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
可以从代码看到,对于SSLContext,在做单向认证时,只需要TrustManagerFactory即可,
context.init(null, tm, null);
TrustManagerFactory是使用了服务端的证书的,即只使用了公钥来加密数据。
如果只需要信任系统自带的证书
SSLContext sslContext = SSLContext.getDefault();
如果需要信任自己的以及系统的证书
引用:http://stackoverflow.com/questions/24555890/using-a-custom-truststore-in-java-as-well-as-the-default-one?noredirect=1
TrustManagerFactory tmf = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm());// Using null here initialises the TMF with the default trust store.tmf.init((KeyStore) null);// Get hold of the default trust managerX509TrustManager defaultTm = null;for (TrustManager tm : tmf.getTrustManagers()) { if (tm instanceof X509TrustManager) { defaultTm = (X509TrustManager) tm; break; }}FileInputStream myKeys = new FileInputStream("truststore.jks");// Do the same with your trust store this time// Adapt how you load the keystore to your needsKeyStore myTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());myTrustStore.load(myKeys, "password".toCharArray());myKeys.close();tmf = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm());tmf.init(myTrustStore);// Get hold of the default trust managerX509TrustManager myTm = null;for (TrustManager tm : tmf.getTrustManagers()) { if (tm instanceof X509TrustManager) { myTm = (X509TrustManager) tm; break; }}// Wrap it in your own class.final X509TrustManager finalDefaultTm = defaultTm;final X509TrustManager finalMyTm = myTm;X509TrustManager customTm = new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { // If you're planning to use client-cert auth, // merge results from "defaultTm" and "myTm". return finalDefaultTm.getAcceptedIssuers(); } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { try { finalMyTm.checkServerTrusted(chain, authType); } catch (CertificateException e) { // This will throw another CertificateException if this fails too. finalDefaultTm.checkServerTrusted(chain, authType); } } @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { // If you're planning to use client-cert auth, // do the same as checking the server. finalDefaultTm.checkClientTrusted(chain, authType); }};SSLContext sslContext = SSLContext.getInstance("TLS");sslContext.init(null, new TrustManager[] { customTm }, null);
问题4:可以看到SSLContext.init()的参数有KeyManager和TrustManager,它俩的差异是?
KeyManager是服务端用的,用于在客户端请求时发送证书及其公钥。
可以看这个链接
http://stackoverflow.com/questions/13997419/difference-between-keystore-and-keymanager-trustmanager
问题5:服务器端会在连接时向客户端发送证书,那么如何从代码上获取?
引用:http://www.xinotes.net/notes/note/1088/
import java.io.InputStream;import java.io.OutputStream;import java.security.cert.X509Certificate;import javax.net.ssl.SSLContext;import javax.net.ssl.SSLSocket;import javax.net.ssl.SSLSession;import javax.net.ssl.SSLSocketFactory;import javax.net.ssl.TrustManager;import javax.net.ssl.X509TrustManager;public class RetrieveSSLCert { public static void main(String[] args) throws Exception { if (args.length < 2) { System.out.println("Usage: java RetrieveSSLCert <host> <port>"); return; } String host = args[0]; int port = Integer.parseInt(args[1]); // create custom trust manager to ignore trust paths TrustManager trm = new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } }; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, new TrustManager[] { trm }, null); SSLSocketFactory factory =sc.getSocketFactory(); SSLSocket socket =(SSLSocket)factory.createSocket(host, port); socket.startHandshake(); SSLSession session = socket.getSession(); java.security.cert.Certificate[] servercerts = session.getPeerCertificates(); for (int i = 0; i < servercerts.length; i++) { System.out.print("-----BEGIN CERTIFICATE-----\n"); System.out.print(new sun.misc.BASE64Encoder().encode(servercerts[i].getEncoded())); System.out.print("\n-----END CERTIFICATE-----\n"); } socket.close(); }}
- Java SSL 证书细节
- Java SSL证书问题
- 配置java服务端SSL证书
- SSL证书SOCKET登陆JAVA
- java web SSL安全证书
- Java SSL 自签名证书生成
- JAVA中SSL证书认证通讯-Client
- Java SSL 自签名证书生成
- Java SSL 自签名证书生成
- java ssl https 连接详解 生成证书
- java ssl https 连接详解 生成证书
- java ssl https 连接详解 生成证书
- java ssl https 连接详解 生成证书
- Java SSL 自签名证书生成
- JAVA SSL HTTPS 连接详解 生成证书
- Java:为jre添加SSL证书
- JAVA SSL HTTPS 链接详解 生成证书
- java ssl https 连接详解 生成证书
- 函数的重载,重写,隐藏
- Leetcode 236. Lowest Common Ancestor of a Binary Tree
- 动态包含与静态包含的区别
- 06-在分布式数据库中CAP原理CAP+BASE学习
- [vijos 1677] 陶陶的名字(kmp)
- Java SSL 证书细节
- datatables表单分页,国外的
- request.getParameter() 和request.getAttribute() 区别
- 这一次,让我们来好好聊聊Java泛型
- JAVA: httpclient 详解——第二章;
- HttpClient 对 cookie的处理
- flex 布局
- HDU 2546 饭卡(0-1背包)
- Docker误区、技巧、转换关系