Ubuntu Tomcat8.5 openssl构建单双向https认证

作为最近学到的新知识的总结吧,好记性不如烂笔头写在这里,也方便以后忘了的时候查看用。

1、 使用openssl生成证书文件

1.1 准备工作

创建工作目录

mkdir ~/demo
cd ~/demo
mkdir -p ca/certs ca/csr ca/private
mkdir -p server/certs server/csr server/private
mkdir -p client/certs client/csr client/private

certs:存放证书文件
csr:存放证书请求文件
private:存放私钥文件


1.2 生成根正书

相当于CA的签发机构,linux下的Chrom和Firefox浏览器都能正常工作,windows下的IE能工作,windows下的Chrome目前没调试好,总是报证书错误(难道windows下不相信所有非真正的CA根证书么),有知道的麻烦告知一下,谢谢。

1.2.1 生成CA私钥
openssl genrsa -out ca/private/ca-key.pem 2048

也可以是1024或者4096位的key,如果需要密码保护,可以使用下面的命令

openssl genrsa -aes256 -out ca/private/ca-key.pem 2048

我为了测试学习,目前没有使用-aes256参数

1.2.2 生成根证书签发申请
openssl req -new -key ca/private/ca-key.pem -out ca/csr/ca-req.csr

如果上一步有密码,此时需要输入上一步的密码

1.2.3 签发根证书

属于自己给自己签发,跟12306的SRCA性质一样

openssl x509 -req -days 365 -sha256 -extensions v3_ca -signkey ca/private/ca-key.pem -in ca/csr/ca-req.csr -out ca/certs/ca-cert.cer

这样我们就有了签发机构了,可以给其它人签发证书了。


1.3 签发服务端证书

1.3.1 生成私钥
openssl genrsa -out server/private/server-key.pem 2048
1.3.2 生成服务端签发申请
openssl req -new -key server/private/server-key.pem -out server/csr/server-req.csr

注意,此证书中的Common Name(cn)是你要发布网站的域名,如www.mytest.com也可以是ip地址,就是浏览器或者客户端输入的那个地址

1.3.3 签发服务端证书
openssl x509 -req -days 365 -sha256 -extensions v3_req -CA ca/certs/ca-cert.cer -CAkey ca/private/ca-key.pem -CAserial ca/ca.srl -CAcreateserial -in server/csr/server-req.csr -out server/certs/server-cert.cer

1.4 签发客户端证书

1.4.1 生成私钥
openssl genrsa -out client/private/client-key.pem 2048
1.4.2 生成客户端签发申请
openssl req -new -key client/private/client-key.pem -out client/csr/client-req.csr

注意,此证书中的Common Name(cn)是你要发布网站的域名,如www.mytest.com也可以是ip地址(后面的双向认证使用),就是浏览器或者客户端输入的那个地址

1.4.3 签发客户端证书
openssl x509 -req -days 365 -sha256 -extensions v3_req -CA ca/certs/ca-cert.cer -CAkey ca/private/ca-key.pem -CAserial ca/ca.srl -CAcreateserial -in client/csr/client-req.csr -out client/certs/client-cert.cer

1.5 证书的使用

1.5.1 转换格式

需要先装其转换成PKCS#12编码格式的密钥库,才能使用keytool工具进行相应的管理。

openssl pkcs12 -export -clcerts -name client -inkey client/private/client-key.pem -in client/certs/client-cert.cer -out client/certs/client-cert.p12
openssl pkcs12 -export -clcerts -name server -inkey server/private/server-key.pem -in server/certs/server-cert.cer -out server/certs/server-cert.p12
1.5.2 生成服务端的信任根证书(双向认证使用)
keytool -importcert -trustcacerts -alias server-trust -file ca/certs/ca-cert.cer -keystore ca/server-trust.p12

其中的-alias参数用于标识证书名字,可以取任意值

1.5.3 生成Android客户端的信任根证书(双向认证使用)

Android端使用的根证书的格式是BKS的(需要专门的一个jar包生成点此下载),安全度更高,据说修改一个bit的数据就会产生错误,反正就是安全级别更高。

keytool -importcert -trustcacerts -alias android-client-trust -file ca/certs/ca-cert.cer -keystore ca/android-client-trust.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ./bcprov-jdk15on-157.jar

此时我们将有这些文件

demo/
├── bcprov-jdk15on-157.jar
├── ca
│   ├── android-client-trust.bks
│   ├── ca.srl
│   ├── certs
│   │   └── ca-cert.cer
│   ├── csr
│   │   └── ca-req.csr
│   ├── private
│   │   └── ca-key.pem
│   └── server-trust.p12
├── client
│   ├── certs
│   │   ├── client-cert.cer
│   │   └── client-cert.p12
│   ├── csr
│   │   └── client-req.csr
│   └── private
│       └── client-key.pem
└── server
    ├── certs
    │   ├── server-cert.cer
    │   └── server-cert.p12
    ├── csr
    │   └── server-req.csr
    └── private
        └── server-key.pem

12 directories, 15 files

常用到的证书文件如下:

./ca/android-client-trust.bks /*Android端的根证书安装文件*/
./ca/server-trust.p12 /*服务器端的信任根证书安装文件(双向认证时使用),比如tomcat使用的*/
./ca/certs/ca-cert.cer /*通常是PC端浏览器上需要安装的*/
./client/certs/client-cert.p12 /*客户端证书,通常用于Android上使用*/
./client/certs/client-cert.cer /*客户端证书,通常用于PC端的浏览器上安装使用*/
./server/certs/server-cert.p12 /*服务器端使用的证书,比如tomcat*/

大概分析一下这些证书之间的关系,技术太差,如果错误,非常非常欢迎指出,非常感谢!!!
首先“./ca/android-client-trust.bks”、“./ca/server-trust.p12”和“./ca/certs/ca-cert.cer”可以看成是一样作用的文件,甚至可以看成一个文件,都是根证书,只是格式不一样。
“./ca/certs/ca-cert.cer”用openssl产生的;
“./ca/server-trust.p12”用keytool产生的,用于java环境下的证书;
“./ca/android-client-trust.bks”用BKS工具产生;
他们签发了Client的“./client/certs/client-cert.p12”证书和Server的“./server/certs/server-cert.p12”证书。

  • 单向认证中
    1、tomcat服务器端部署证书“./server/certs/server-cert.p12”
    2、PC端浏览器安装根证书“./ca/certs/ca-cert.cer”
    3、Android客户端安装根证书“./ca/android-client-trust.bks”
    当客户端向服务器请求时,服务器将自己的证书给客户端,客户端根据服务器的证书中的CA根证书名字,找到自己安装的根证书来验证服务器的证书,由于服务器的证书是客户端安装的根证书签发的,所以,客户端能认证通过,然后进行安全会话。

  • 双向认证中
    在单项认证基础上
    1、tomcat服务器端部署信任根证书“./ca/server-trust.p12”;
    2、PC端浏览器安装证书“./client/certs/client-cert.cer”;
    3、Android客户端安装证书“./client/certs/client-cert.p12”
    当客户端向服务器请求时,客户端将自己的证书发给服务器,服务器更加客户端证书中的CA根证书名字,找到自己安装的根证书来验证客户端的证书,由于客户端的证书是服务器安装的根证书签发的,所以,服务器能认证通过;然后服务器将自己的证书发给客户端,客户端在用自己的CA根证书验证服务器的证书,验证通过,就可以进行安全会话,之间只要有任何不通过的地方,双方通信立刻停止。




2、单向认证的配置

2.1 Tomcat配置

打开Tomcat配置文件server.xml,增加如下内容:

<Connector
    port="8443"
    protocol="HTTP/1.1"
    maxThreads="150"
    SSLEnabled="true"
    scheme="https"
    secure="true"
    clientAuth="false"
    sslProtocol="TLS"
    keystoreFile="{绝对路径}/server-cert.p12"
    keystoreType="pkcs12"
    keystorePass="123456"
    />

如果是本机测试,而且是用的域名,可以将“/etc/hosts”文件中的localhost修改为自己的域名。
我本机搭建的tomcat服务器地址的我的ip地址(192.168.7.215),所以我都是以这个ip地址测试。


2.2 chrome测试

打开chrome,输入https://192.168.7.215:8443提示如下图:
这里写图片描述

此时添加我们CA根证书(./ca/certs/ca-cert.cer),来使chrome能正确验证我们自签发的服务端证书,一定要导入到授权中心,并勾选所有选择框。
这里写图片描述

在次刷新浏览器,可以看到已经认证成功,进行了https安全会话。
这里写图片描述


2.3 Android客户端测试

在Android中使用我们自己生成的根证书,使用方法如下:

private static final String KEY_STORE_TRUST_FILE = "/data/data/你自己app的包名/files/android-client-trust.bks";
private static final String KEY_STORE_TRUST_PASS = "123456";

private static final String KEY_STORE_TYPE_BKS = "bks";

KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS);
InputStream tsin = new FileInputStream(KEY_STORE_TRUST_FILE);
trustStore.load(tsin, KEY_STORE_TRUST_PASS.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();

SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustManagers, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

看网上很多都使用信任任何证书的方式访问https,我觉得不安全,但我又不知道如何使用系统自带的根证书去认证,有知道的麻烦告知一下,非常感谢!!!




3、双向认证配置

3.1 Tomcat配置

<Connector
    port="8443"
    protocol="HTTP/1.1"
    maxThreads="150"
    SSLEnabled="true"
    scheme="https"
    secure="true"
    clientAuth="true"
    sslProtocol="TLS"
    keystoreFile="{绝对路径}/server-cert.p12"
    keystoreType="pkcs12"
    keystorePass="123456"
    truststoreFile="{绝对路径}/server-trust.p12"
    truststoreType="jks"
    truststorePass="123456"
    />

3.2 chrome测试

由于tomcat配置的是clientAuth=”true”,表示客户端也必须有证书,此时没有导入客户端证书,所以直接不能访问:
这里写图片描述

导入浏览器证书(./client/certs/client-cert.cer),需要导入到“您的证书”列表中,对于Firefox也是导入到这里面,不要导入到“个人”中
这里写图片描述
再次刷新页面:
这里写图片描述
需要选择证书,此时选择我们导入的证书,再次栓新页面:
这里写图片描述

3.3 Android客户端测试

代码如下,主要是添加客户端使用的证书

private static final String KEY_STORE_CLIENT_FILE = "/data/data/你自己app的包名/files/client-cert.p12";
private static final String KEY_STORE_CLIENT_PASS = "123456";

private static final String KEY_STORE_TRUST_FILE = "/data/data/你自己app的包名/files/android-client-trust.bks";
private static final String KEY_STORE_TRUST_PASS = "123456";

private static final String KEY_STORE_TYPE_BKS = "bks";
private static final String KEY_STORE_TYPE_P12 = "PKCS12";

KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
InputStream ksin = new FileInputStream(KEY_STORE_CLIENT_FILE);
keyStore.load(ksin, KEY_STORE_CLIENT_PASS.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(keyStore, KEY_STORE_CLIENT_PASS.toCharArray());
KeyManager[] keyManagers = kmf.getKeyManagers();

KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS);
InputStream tsin = new FileInputStream(KEY_STORE_TRUST_FILE);
trustStore.load(tsin, KEY_STORE_TRUST_PASS.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();

SSLContext sc = SSLContext.getInstance("TLS");
sc.init(keyManagers, trustManagers, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

其它

如下配置,能使浏览器访问时不用输入http或者https,直接输入ip或者域名,都自动使用https访问。
打开tomcat的web.xml,在</welcome-file-list>下面添加如下代码:

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>

<login-config>
    <!-- Authorization setting for SSL -->
    <auth-method>CLIENT-CERT</auth-method>
    <realm-name>Client Cert Users-only Area</realm-name>
</login-config>
<security-constraint>
    <!-- Authorization setting for SSL -->
    <web-resource-collection >
        <web-resource-name >SSL</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

重启tomcat即可。


其实这里还有SNI(Server Name Indication)方面的知识,是为了解决一个服务器使用多个域名和证书的SSL/TLS扩展,网上有很多介绍的,下图是我访问百度的抓包,里面有SNI扩展字段
这里写图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值