前言
最近几年各大主流网站对HTTPS支持的越来越完善,之前很多网站只有关键的登录、下单等操作页面支持HTTPS,现在已经逐步的改为全站HTTPS。使用HTTPS协议浏览器与服务器交互过程中除了内容加密还有对服务器和身份的验证,比如用浏览器去访问淘宝网浏览器通过验证淘宝网服务器证书的正确性保证访问的是真实的淘宝网
本文记录下使用Tomcat配置HTTPS单向和双向认证配置过程,以及使用Apache HttpClient组件访问https服务过程
本文假设线上环境HTTPS单向认证域名weibo.com,双向认证域名tmall.com(注:这只随机选了weibo和tmall域名做测试而已,跟微博天猫官方没一毛钱关系),客户端通过修改hosts,访问对应的服务器
Tomcat HTTPS单向认证配置
1 生成证书
- 生成服务器证书库
keytool -genkey -keyalg RSA -alias weibo_server -dname "CN=weibo.com" -keystore weibo_server.keystore -storepass weiboweibo -ext san=dns:weibo.com
- 生成证书请求csr文件,主要是提交给CA注册验证用,由于本次证书配置没有提交真正的CA认证,需要在 3)步生成的证书发给客户端导入
keytool -certreq -alias weibo_server -keystore weibo_server.keystore -file weibo_ca.csr
- 生成证书文件,提供给客户端导入使用
keytool -export -alias weibo_server -keystore weibo_server.keystore -file weibo_ca.cer -storepass weiboweibo
2 Tomcat配置,启用HTTPS,其中clientAuth="false"表示客户端不需要认证
<Connector SSLEnabled="true" clientAuth="false"
maxThreads="150" port="8443"
protocol="org.apache.coyote.http11.Http11Protocol"
scheme="https" secure="true" sslProtocol="TLS"
keystoreFile="/dev/https_config/tomcat/weibo_server.keystore" keystorePass="weiboweibo"/>
3 客户端证书导入和访问
1) 浏览器访问
本人使用Mac电脑,点击weibo_ca.cer文件,即可导入证书到Mac的密钥串访问程序里,然后在密钥串访问左上角选“登录”菜单,左下角选“证书”,在右边的weibo.com里点击打开,点“信任”,选择“使用此证书时”的“始终信任”
如图
(Windows操作系统过程应该类似,手头没有Windows不方便验证,这里跳过)
然后浏览器里输入网址
https://weibo.com:8443/ 即可看地址栏加锁的绿色图标
2) Java客户端访问
由于java语言的特殊性,它有自己一套CA证书和密钥管理机制,有自己内置的根证书列表。操作系统已经导入的证书不能使用,需要把证书手动导入到JVM的证书目录下 ,该目录一般为
JAVA_HOME/jre/lib/security/cacerts
线上环境处于运维复杂性的考虑,手动导入证书到证书目录里不一定合适,可以在代码里指定需要加载的证书
方法一 System.Property里指定服务器证书
@Test
public void testWithSystemProperty() throws Exception {
System.setProperty("javax.net.ssl.trustStore",
System.getProperty("user.home") + "/dev/https_config/tomcat/weibo_server.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "weiboweibo");
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("https://weibo.com:8443/");
CloseableHttpResponse response = httpclient.execute(httpget);
System.out.println(response.getStatusLine() + ":" + IOUtils.toString(response.getEntity().getContent()));
}
方法二 代码里主动加载证书
@Test
public void testWithLoadTrustStore() throws Exception {
SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(new File(System.getProperty("user.home")
+ "/dev/https_config/tomcat/weibo_server.keystore"),
"weiboweibo".toCharArray(),
new TrustSelfSignedStrategy()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
try {
HttpGet httpget = new HttpGet("https://weibo.com:8443/");
System.out.println("Executing request " + httpget.getRequestLine());
CloseableHttpResponse response = httpclient.execute(httpget);
System.out.println(response.getStatusLine() + ":" + IOUtils.toString(response.getEntity().getContent()));
} finally {
httpclient.close();
}
}
方法三,把服务器证书导入到JDK的cacert里
sudo keytool -import -alias weibo_cert -file "weibo_server.cer" -keystore "/Library/Java/JavaVirtualMachines/jdk1.8.0_73.jdk/Contents/Home/jre/lib/security/cacerts" -storepass weiboweibo
httpclient代码里证书指定的代码可以省略了
@Test
public void test1() throws Exception{
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("https://wrj.me:8443/");
CloseableHttpResponse response = httpclient.execute(httpget);
System.out.println(response.getStatusLine()+":"+ IOUtils.toString(response.getEntity().getContent()));
}
到此为止,HTTPS单向认证配置和访问已经结束,下面来说说HTTPS双向认证配置和访问过程
Tomcat HTTPS双向认证配置
单向认证,只有客户端验证服务器证书和真实服务器身份是否一致,双向认证服务器也会认证客户端真实身份,大部分互联网网站都是单向认证,除了网银之类比较特殊的应用,双向认证假设域名是tmall.com,服务器证书密码用tmalltmall,客户端证书密码是tmallclient
1 服务端和客户端证书生成
先建立两个目录server和client,分别作为输出服务器和客户端证书目录
- 生成服务端证书库
keytool -genkey -v -alias tmall_server -keyalg RSA -keystore server/tmall_server.keystore -validity 36500 -dname "CN=tmall.com" -ext san=dns:tmall.com
2)生成客户端证书
keytool -genkey -v -alias tmall_client -keyalg RSA -storetype PKCS12 -keystore client/tmall_client.p12
2 让服务器信任客户端证书
(1)由于不能直接将PKCS12格式的证书库导入,必须先把客户端证书导出为一个单独的CER文件,使用如下命令:
(下面要用到客户端证书密码“tmallclient”)
keytool -export -alias tmall_client -keystore client/tmall_client.p12 -storetype PKCS12 -storepass tmallclient -rfc -file client/tmall_client.cer
(2)将该客户端证书文件导入到服务器的证书库,添加为一个信任证书:
keytool -import -v -file client/tmall_client.cer -keystore server/tmall_server.keystore
(3)通过 list 命令查看服务器的证书库,可以看到两个证书,一个是服务器证书,一个是受信任的客户端证书:
keytool -list -keystore server/tmall_server.keystore
3 让客户端信任服务器证书
由于是双向SSL认证,客户端也要验证服务器证书。把服务器证书导出为一个单独的CER文件提供给客户端,使用如下命令:
keytool -keystore server/tmall_server.keystore -export -alias tmall_server -file server/tmall_server.cer
把 server/tmall_server.cer(服务端自签名证书) 和client/tmall_client.cer(为客户端生成的证书),client/tmall_client.cer(客户端密钥对) 提供给客户端
客户端导入服务器证书server/tmall_server.cer和服务器颁发给客户端的证书client/tmall_client.cer,密钥对client/tmall_client.p12
4 配置tomcat
tomcat server.xml文件配置
<Connector SSLEnabled="true" clientAuth="true"
maxThreads="150" port="8443"
protocol="org.apache.coyote.http11.Http11Protocol"
scheme="https" secure="true" sslProtocol="TLS"
keystoreFile="/dev/https_config/tomcat/bidirection/server/tmall_server.keystore"
keystorePass="tmalltmall"
truststoreFile="/dev/https_config/tomcat/bidirection/server/tmall_server.keystore"
truststorePass="tmalltmall"
/>
重启tomcat
5 浏览器访问
客户端配置hosts,tmall.com域名映射到服务器ip
浏览器输入https://tmall.com:8443/
提示选择证书
6 apache httpclient访问
@Test
public void testWithLoadCert() throws Exception {
// Trust own CA and all self-signed certs
SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(new File(System.getProperty("user.home")
+ "/dev/https_config/tomcat/bidirection/server/tmall_server.keystore"),
"tmalltmall".toCharArray(),
new TrustSelfSignedStrategy()).loadKeyMaterial(new File(System.getProperty("user.home")
+ "/dev/https_config/tomcat/bidirection/client/tmall_client.p12"),
"tmallclient".toCharArray(),
"tmallclient".toCharArray()).build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
try {
HttpGet httpget = new HttpGet("https://tmall.com:8443/");
System.out.println("Executing request " + httpget.getRequestLine());
CloseableHttpResponse response = httpclient.execute(httpget);
System.out.println(response.getStatusLine() + ":" + IOUtils.toString(response.getEntity().getContent()));
} finally {
httpclient.close();
}
}
loadTrustMaterial加载服务器证书,loadKeyMaterial加载服务器提供给客户端证书,如果该服务器证书已经内置Java cacert文件,可以省略loadTrustMaterial
总结
HTTPS是密码学在信息安全领域综合应用体现,融合对称加密、非对称加密、消息摘要、数字签名、密钥交换、随机数、证书等知识。相关知识请自行搜索学习。
按照一般的线上环境部署,nginx之类前置反向代理服务器做HTTPS卸载,由nginx转发到tomcat、jboss等应用服务器,证书配置在nginx里。