https
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了https相关的知识,希望对你有一定的参考价值。
#概述
https 基本过程是
1.客户端发送请求,请求包含客户端支持的非对称加密方式,等等
2.服务器返回公钥(证书)
3.客户端用公钥加密对称密钥后返回给服务器
4.服务器用私钥解密后得到对称密钥,
5.两者用对称密钥通讯
#证书验证
关于证书,首先证书的作用是为了证明服务端的可靠性,设想一种情景 如果第二步服务端返回的是裸的公钥,没有证书,那么会有怎样的安全问题
服务器----中间人------客户端
如果中间人角色劫持了报文,将自己的公钥发给客户端,那么中间人就可以代替客户端和服务器通讯,起到劫持报文的效果,
那么如果发送的是证书,会怎样验证:
1.假设服务端通过CA的验证,那么服务端证书中就有一个CA对证书的签名,签名方法sign= CA_privateKey(hash(content)),
2.客户端拿到证书之后,对证书hash,得到值之后,用CA_publicKey对证书中签名解码,得到证书的hash,对比两个hash是否相同,
3.如果不通过CA,而是通过CA下的二级组织,那么就逐级解码,直到有一个能解码,
4.所以只要客户没有安装中间人的证书,并且CA私钥不泄露,那么https就是安全的
#tomcat开启https
###1. 首先用keytool工具产生.keystore文件,这个文件包含公钥私钥,用.keystore文件可以产生.crt的证书文件,只包含公钥,
关于keystore ,crt ,cacerts的概念:keystore是包含公钥私钥的文件,crt是证书(密钥库),只包含公钥,cacerts是jre中信任的证书(密钥库),
这里证书,密钥,密钥库的概念有些混淆,三个概念有点一样,
**生成keystore**
> keytool -genkeypair -alias "test1" -keyalg "RSA" -keystore "test.keystore"
>-genkeypair:生成一对非对称密钥;
>-alias:指定密钥对的别名,该别名是公开的;
>-keyalg:指定加密算法,本例中的采用通用的RAS加密算法;
>-keystore:密钥库的路径及名称,不指定的话,默认在操作系统的用户目录下生成一个".keystore"的文件
**查看cacerts中的证书**
>keytool -rfc -list -keystore "%JAVA_HOME%/jre/lib/security/cacerts
>默认密钥changeit
>-list 命令打印证书的 MD5 指纹。而如果指定了 -v 选项,将以可读格式打印证书,如果指定了 -rfc 选项,将以可打印的编码格式输出证书。
**导出证书**
>keytool -export -alias tomcat -keystore tomcat.keystore -file tomcat.crt
**导入证书到cacerts**
>keytool -import -keystore "%JAVA_HOME%\jre\lib\security\cacerts" -file tomcat.crt -alias tomcat
**从cacerts删除密钥(需要管理员的权限)**
>keytool -delete -alias tomcat -keystore "%JAVA_HOME%\jre\lib\security\cacerts"
### 2. 在tomcat的server.xml中开启并指定.keystore文件,及密码
```
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="g:\tomcat.keystore"
keystorePass="123456"
/>
```
指定之后tomcat的https就被开启
#java代码客户端如何处理证书
java的httpsurlConnection 可以进行https连接,但是由于https中客户端需要安装证书,所以java的https证书这一块需要特定操作,
__实例化信任管理器__
```
public class TrustAnyTrustManager implements X509TrustManager{
/* 该方法检查客户端的证书,若不信任该证书则抛出异常。由于我们不需要对客户端进行认证,因此我们只需要执行默认的信任管理器的这个方法。JSSE中,默认的信任管理器类为TrustManager。
* @see javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String)
*/
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
/* 该方法检查服务器的证书,若不信任该证书同样抛出异常。通过自己实现该方法,可以使之信任我们指定的任何证书。在实现该方法时,也可以简单的不做任何处理,即一个空的函数体,由于不会抛出异常,它就会信任任何证书。
* @see javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String)
*/
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
if(Certificates.DLCCertificate!=null && Certificates.DLCCertificate.equals(chain[0])) {
}else {
throw new CertificateException();
}
}
/* 返回受信任的X509证书数组。
* @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
*/
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
```
__流读取证书进行验证__
```
try {
InputStream inStream = Certificates.class.getResourceAsStream("/config/Certificate/1214316744.crt");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
inStream.close();
DLCCertificate = cert;
} catch (CertificateException | IOException e) {
LOG.error("\u52a0\u8f7d\u8bc1\u4e66\u5931\u8d25");//加载证书失败
}
```
X509Certificate 的equals方法可以进行证书的比较
__安装证书到jre__
用keytool工具加载到cacerts之后就可以不再用自己验证了,但是要注意一点keytool生成ketstore时名字姓氏要写域名,如果是IP,在连接时会不符合,可以实现HostnameVerifier来忽略这一步
***
**补充内容和参考**
关于双向 单向
我们知道TLS协议中验证证书可以是双向的,即服务端也要验证客户端的身份来防止客户端的伪冒,
但是这种场景在一般基于web的https中很少(通过U盾的网银是例外,
U盾其实就是客户端证书,但这样也非常繁琐),因为基于web的应用客户数量大,
很难为每个客户去提供相应的数字证书。但是对于一些企业之间的对接,出于安全考虑,
很多情况下会采用双向认证的方式,因为对于两个企业来说也不存在client、server端的说法。
关于巨复杂的对称密钥生成方法
http://www.jianshu.com/p/a766bbf31417
关于握手
http://blog.csdn.net/hherima/article/details/52469674
关于keytool
http://ln-ydc.iteye.com/blog/1335213
以上是关于https的主要内容,如果未能解决你的问题,请参考以下文章