对于HTTPS、TLS、SSL相关的概念,平时也是时常接触到。看过几篇文章之后,总以为自己真正了解了,实际上碰到问题时才知道,自己恐怕连入门都算不上。所以打算入个门,补上这一部分的基础知识,对于更深层次的东西,例如各种标准的解读,则不打算深入。
我们都知道HTTP是不安全的,以及为什么不安全。但是为了更直观的说明以及加深理解,做一个简单的模拟,我使用WireShark作为辅助工具。
本地建一个简单Restful Java项目,并部署到Tomcat中。
我们只去抓本地的包,所以在开始抓包之前,在用户界面中选择Loopback, 并设置Capture Filter
src host localhost and dst host localhost
Capture Filter的相关语法可以在 WireShark软件用户界面 > Help > Wiki > CaptureFilters 中找到 > Further Information(pcap-filter man page ) 全部语法
本地启动测试程序, IDEA中Tomcat的配置中应该只配HTTP Port,我这里配置的是8080.
在终端进行post请求
curl -X POST http://localhost:8080/validation/valid/inline/post
设置Display Filter
http and tcp.port eq 8080
上面的场景模拟概括成一句话就是: HTTP是裸奔的。任何数据在网络中传播都是以明文的形式,使用抓包工具即可截获报文,甚至可能对其进行修改。这种危害可太恐怖了,所有使用网络与各种服务交互的人,各种隐私轻轻松松就泄露出去了。
为了解决裸奔的问题,势必要对通信进行加密并解决中间人攻击问题。
关于为什么需要加密,更详细的说明可参考cloudflare官方的一篇博客,比我的语言更准确。以下内容引自上述博客的中文版
隐私:加密可确保除预期的收件人或正当的数据所有者以外,任何人都无法读取静止的通信或数据。这可以防止攻击者、广告网络、互联网服务提供商以及(在某些情况下)政府拦截和读取敏感数据,保护用户隐私。
安全性:无论是传输中的数据还是静止数据,加密都有助于防止数据泄露。如果公司设备丢失或被盗,且其硬盘驱动器已适当加密,则该设备上的数据将仍是安全的。类似地,加密通信使通信双方能够交换敏感数据而不会泄露数据。
数据完整性: 加密还有助于防止恶意行为,如在途攻击。当数据在互联网上传输时,加密可确保收件人收到的内容在途中没有被查看或篡改过。
法规:出于所有这些原因,许多行业和政府法规要求处理用户数据的公司对这些数据进行加密。需要加密的法规与合规性标准的示例包括 HIPAA、PCI-DSS 和 GDPR。
那么如何解决中间人攻击呢?下文CA证书部分会详细解释。
对称加密的只有一把key,这个key既可以用来加密信息,也可以用来解密信息。
这就是它的缺点,只要能拿到密钥,则可以解密、加密信息。
非对称加密使用两把key,它解决了上述对称加密的缺点。一把key-1加密的信息必须由其对应的另外一把key-2才能解密,key-1本身不能再解密这个信息。这里要理解的是,两把key可以互相加解密。具体哪把key加密,哪把key解密是根据使用场景来说的。以下内容引用自阿里云官方文档
通过加密算法得到的密钥对可以保证在世界范围内是唯一的。使用密钥对的时候,如果用其中一个密钥加密一段数据,只能使用密钥对中的另一个密钥才能解密数据。例如:用公钥加密的数据必须用对应的私钥才能解密;如果用私钥进行加密也必须使用对应的公钥才能解密,否则将无法成功解密
以下内容引用自阿里云官方文档
每个用户自己设定一把特定的、仅为本人所知的私有密钥(私钥),并用它进行解密和签名;同时设定一把公共密钥(公钥)并由本人公开,为一组用户所共享,用于加密和验证签名。
由于密钥仅为本人所有,可以产生其他人无法生成的加密文件,也就是形成了数字签名
根据以上内容,当我们把公钥告诉别人的时候,对方使用我们的公钥加密我们直接的信息,由于只有我们得私钥才能解密,所以即使这个信息丢失或者被盗,其他人也无法知道原始信息是什么,这就解决了上述所说的隐私性、安全性的问题
数据完整性如何保证呢?以下内容引自Linux公社
当加密数据时,使用单向加密算法,通过hash函数计算出数据独一无二的校验码,这个校验码称为“信息摘要(Message Digest)”。
对于数据来源可靠性,使用自己的私钥加密即可验证身份,因为获得数据后使用公钥不能解密的就证明数据不是配对私钥加密的。但是私钥加密速度慢,所以只用私钥加密摘要信息,加密后的摘要信息称为“数字签名(Signature)”
根据以上内容,当我们用私钥对数据的信息摘要进行加密时,所有拥有我们公钥的人都可以解密获得这部分信息摘要,这是告诉对方,这条信息确确实实来自于我。
为了加深公钥和私钥的使用,可以使用在线网站自己体验一下,这里有一个体验RSA加解密的网站
不管是对称加密还是非对称加密,都有一个问题是如何解决中间人攻击?
于是引入信任的第三方机构来解决, 来自keystore文档中的解释
In a large-scale networked environment, it is impossible to guarantee that prior relationships between communicating entities were established or that a trusted repository exists with all used public keys. Certificates were invented as a solution to this public key distribution problem. Now a Certification Authority (CA) can act as a trusted third party
可以看到,CA机构主要的作用就是告诉客户端连接的是真正的想要通信的服务端,而不是中间人所伪造出来的。
但是问题又来了,中间人攻击既然可以冒充服务器,为什么不能冒充CA机构呢?
当CA机构把证书返回给客户端时,客户端要使用CA机构的公钥去验证该证书的数字签名是不是真的CA机构签发的。那CA机构的公钥也很多吗?
这带来几个疑问
快捷命令
keytool -h
下列命令会生成密钥对和自签名证书
keytool -genkey -alias tomcat -keyalg RSA
genkey和genkeypair是一样的
The command uses the default SHA256withRSA signature algorithm to create a self-signed certificate that includes the public key and the distinguished name information. The certificate is valid for 180 days
默认生成的文件名是.keystore,引用自Keytool文档说明
For example, if keytool -genkeypair is called and the -keystore option isn’t specified, the default keystore file named .keystore is created in the user’s home directory if it doesn’t already exist
除了keytool,我一般使用KeyStore Explorer直接点点点生成,毕竟各种命令太多也记不住,不如直接用鼠标点一点来的方便
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig>
<Certificate
certificateKeystoreFile="${user.home}/.keystore"
certificateKeystorePassword="changeit"
type="RSA" />
SSLHostConfig>
Connector>
Tomcat配置SSL的官方完整文档
Tomcat重启之后,打开浏览器访问 https://localhost:8443/validation/,还是提示
对于自签名证书,我们需要将其导入到操作系统的指定位置
keytool -export -alias tomcat -keystore .keystore -file tomcat.cer
经过查找资料,对于自签名证书,要设置SubjectAlternativeName,
于是重新删除刚刚生成的key以及导出的证书,重新生成一次
keytool -genkey -alias tomcat -keyalg RSA -ext san=IP:127.0.0.1,DNS:localhost
关于san的写法完整说明,见keytool文档中supported named extension部分
生成完毕,再次导出证书、将其添加到操作系统的指定位置、信任该证书。再次重启Tomcat,再次访问https://localhost:8443/validation/
这次就是我们所期望的,看到了标志
配置好HTTPS之后,我们再次尝试用WireShark抓包
这次我们请求的是https
curl -X POST -k https://localhost:8443/validation/valid/inline/post
tls and tcp.port in {8443, 55026}
可以看到,我们通过WireShark抓到的包都是加密的了,再也看不到裸奔的数据了。
本篇文章简单梳理了一下自己在理解TLS以及公钥、私钥以及CA证书等各个概念时疑问,以及思考。
下一篇将进行TLS握手详细分析