HTTPS
HTTP的一些缺点,其中的“无状态”在加入Cookie后得到了解决,而另两个缺 点----“明文”和“不安全”仅凭HTTP自身是无力解决的,需要引入新的HTTPS协议。
由于HTTP天生“明文”的特点,整个传输过程完全透明,任何人都能够在链路中截获、修改或者伪造请求/ 响应报文,数据不具有可信性。
比如,代理服务。它作为HTTP通信的中间人,在数据上下行的时候可以添加或删除部分头字段,也可以使用黑白名单过滤body里的关键字,甚至直接发送虚假的请求、响应,而浏览器和源服务器都没有办法判断报文的真伪。这对于网络购物、网上银行、证券交易等需要高度信任的应用场景来说是非常致命的。如果没有基本的安全保护,使用互联网进行各种电子商务、电子政务就根本无从谈起。对于安全性要求不那么高的新闻、视频、搜索等网站来说,由于互联网上的恶意用户、恶意代理越来越多, 也很容易遭到“流量劫持”的攻击,在页面里强行嵌入广告,或者分流用户,导致各种利益损失。对于你我这样的普通网民来说,HTTP不安全的隐患就更大了,上网的记录会被轻易截获,网站是否真实也无法验证,黑客可以伪装成银行网站,盗取真实姓名、密码、银行卡等敏感信息,威胁人身安全和财产安全。
什么是安全?
通常认为,如果通信过程具备了四个特性,就可以认为是“安全”的,这四个特性是:机密性、完整性,身份认证和不可否认。
机密性(Secrecy/Confidentiality)是指对数据的“保密”,只能由可信的人访问,对其他人是不可见的“秘密”,简单来说就是不能让不相关的人看到不该看的东西。
完整性(Integrity,也叫一致性)是指数据在传输过程中没有被窜改,不多也不少,“完完整整”地保持着 原状。
身份认证(Authentication)是指确认对方的真实身份,也就是“证明你真的是你”,保证消息只能发送给 可信的人。
第四个特性是不可否认(Non-repudiation/Undeniable),也叫不可抵赖,意思是不能否认已经发生过的行 为,不能“说话不算数”“耍赖皮”。
什么是HTTPS
HTTPS其实是一个“非常简单”的协议,RFC文档很小,只有短短的7页,里面规定了新的协议 名“https”,默认端口号443,至于其他的什么请求-应答模式、报文结构、请求方法、URI、头字段、连接 管理等等都完全沿用HTTP,没有任何新的东西。
HTTPS名字里的“S”,它把HTTP下层的传输协议由TCP/IP换成了SSL/TLS,由“HTTP over TCP/IP”变成了“HTTP over SSL/TLS”,让HTTP运行在了安全的SSL/TLS协议上, 收发报文不再使用Socket API,而是调用专门的安全接口。
SSL/TLS
SSL即安全套接层(Secure Sockets Layer),在OSI模型中处于第5层(会话层),由网景公司于1994年发 明,有v2和v3两个版本,而v1因为有严重的缺陷从未公开过。
SSL发展到v3时已经证明了它自身是一个非常好的安全通信协议,于是互联网工程组IETF在1999年把它改名为TLS(传输层安全,Transport Layer Security),正式标准化,版本号从1.0重新算起,所以TLS1.0实际上就是SSLv3.1。
到今天TLS已经发展出了三个版本,分别是2006年的1.1、2008年的1.2和去年(2018)的1.3,每个新版本都紧跟密码学的发展和互联网的现状,持续强化安全和性能,已经成为了信息安全领域中的权威标准。
目前应用的最广泛的TLS是1.2,而之前的协议(TLS1.1/1.0、SSLv3/v2)都已经被认为是不安全的,各大浏 览器即将在2020年左右停止支持.
TLS由记录协议、握手协议、警告协议、变更密码规范协议、扩展协议等几个子协议组成,综合使用了对称加密、非对称加密、身份认证等许多密码学前沿技术。浏览器和服务器在使用TLS建立连接时需要选择一组恰当的加密算法来实现安全通信,这些算法的组合被称为“密码套件”(cipher suite,也叫加密套件)。
OpenSSL
说到TLS,就不能不谈到OpenSSL,它是一个著名的开源密码学程序库和工具包,几乎支持所有公开的加密 算法和协议,已经成为了事实上的标准,许多应用软件都会使用它作为底层库来实现TLS功能,包括常用的 Web服务器Apache、Nginx等。
常用命令
生成私钥:openssl genrsa -out abc.key
生成公钥:openssl rsa -in abc.key -pubout -out abc.pem
可以使用OpenSSL构建一套属于自己的CA,自己给自己颁发证书,称为“自签名证书”
OpenSSL是从另一个开源库SSLeay发展出来的,曾经考虑命名为“OpenTLS”,但当时(1998年)TLS还未正式确立,而SSL早已广为人知,所以最终使用了“OpenSSL”的名字。
HTTPS建立连接
◼ 总的可以分为3大阶段
1 TCP的3次握手
2 TLS的连接
3 HTTP请求和响应
在HTTP协议里,建立连接后,浏览器会立即发送请求报文。但现在是HTTPS协议,它需要再用另外一 个“握手”过程,在TCP上建立安全连接,之后才是收发HTTP报文。
TLS协议的组成
TLS包含几个子协议,你也可以理解为它是由几个不同职责的模块组成,比较常用的有记录协议、警报协 议、握手协议、变更密码规范协议等。
记录协议(Record Protocol)规定了TLS收发数据的基本单位:记录(record)。它有点像是TCP里的 segment,所有的其他子协议都需要通过记录协议发出。但多个记录数据可以在一个TCP包里一次性发出, 也并不需要像TCP那样返回ACK。
警报协议(Alert Protocol)的职责是向对方发出警报信息,有点像是HTTP协议里的状态码。比如, protocol_version就是不支持旧版本,bad_certificate就是证书有问题,收到警报后另一方可以选择继续,也可以立即终止连接。
握手协议(Handshake Protocol)是TLS里最复杂的子协议,要比TCP的SYN/ACK复杂的多,浏览器和服务器会在握手过程中协商TLS版本号、随机数、密码套件等信息,然后交换证书和密钥参数,最终双方协商得 到会话密钥,用于后续的混合加密系统。
最后一个是变更密码规范协议(Change Cipher Spec Protocol),它非常简单,就是一个“通知”,告诉对方,后续的数据都将使用加密保护。那么反过来,在它之前,数据都是明文的。
在TCP建立连接之后,浏览器会首先发一个“Client Hello”消息,也就是跟服务器“打招呼”。里面有客户 端的版本号、支持的密码套件,还有一个随机数(Client Random),用于后续生成会话密钥。
Handshake Protocol: Client Hello
Version: TLS 1.2 (0x0303)
Random: 1cbf803321fd2623408dfe...
Cipher Suites (17 suites)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
这个的意思就是:“我这边有这些这些信息,你看看哪些是能用的,关键的随机数可得留着。”
服务器收到“Client Hello”后,会返回一个“Server Hello”消息。把版本号对一下, 也给出一个随机数(Server Random),然后从客户端的列表里选一个作为本次通信使用的密码套件,在这 里它选择了“TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384”。
Handshake Protocol: Server Hello
Version: TLS 1.2 (0x0303)
Random: 0e6320f21bae50842e96...
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
这个的意思就是:“版本号对上了,可以加密,你的密码套件挺多,我选一个最合适的吧,用椭圆曲线加 RSA、AES、SHA384。我也给你一个随机数,你也得留着。”
然后,服务器为了证明自己的身份,就把证书也发给了客户端(Server Certificate)。
接下来是一个关键的操作,因为服务器选择了ECDHE算法,所以它会在证书后发送“Server Key Exchange”消息,里面是椭圆曲线的公钥(Server Params),用来实现密钥交换算法,再加上自己的私钥签名认证。为了防止伪造,Server Params经过了服务器私钥签名
Handshake Protocol: Server Key Exchange
EC Diffie-Hellman Server Params
Curve Type: named_curve (0x03)
Named Curve: x25519 (0x001d)
Pubkey: 3b39deaf00217894e...
Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
Signature: 37141adac38ea4...
这相当于说:“刚才我选的密码套件有点复杂,所以再给你个算法的参数,和刚才的随机数一样有用,别丢了。为了防止别人冒充,我又盖了个章。”
之后是“Server Hello Done”消息,服务器说:“我的信息就是这些,打招呼完毕。”
这样第一个消息往返就结束了(两个TCP包),结果是客户端和服务器通过明文共享了三个信息:Client Random、Server Random和Server Params。
客户端这时也拿到了服务器的证书,那这个证书是不是真实有效的呢?开始走证书链逐级验证,确认证书的真实性,再用证书公钥验证签名,就确认了服务器的身份:“刚才跟我打招呼的不是骗子,可以接着往下走。”
然后,客户端按照密码套件的要求,也生成一个椭圆曲线的公钥(Client Params),用“Client Key Exchange”消息发给服务器。
Handshake Protocol: Client Key Exchange
EC Diffie-Hellman Client Params
Pubkey: 8c674d0e08dc27b5eaa...
现在客户端和服务器手里都拿到了密钥交换算法的两个参数(Client Params、Server Params),就用 ECDHE算法一阵算,算出了一个新的东西,叫“Pre-Master”,其实也是一个随机数。
现在客户端和服务器手里有了三个随机数:Client Random、Server Random和Pre-Master。用这三个作为原始材料,就可以生成用于加密会话的主密钥,叫“Master Secret”。而黑客因为拿不到“Pre-Master”,所以也就得不到主密钥。这就必须说TLS的设计者考虑得非常周到了,他们不信任客户端或服务器伪随机数的可靠性,为了保证真正 的“完全随机”“不可预测”,把三个不可靠的随机数混合起来,那么“随机”的程度就非常高了,足够让 黑客难以猜测。
主密钥有48字节,但它也不是最终用于通信的会话密钥,还会再用PRF扩展出更多的密钥,比如客户端发送用的会话密钥(client_write_key)、服务器发送用的会话密钥(server_write_key)等等,避免只用一个密钥带来的安全隐患。
有了主密钥和派生的会话密钥,握手就快结束了。客户端发一个“Change Cipher Spec”,然后再发一 个“Finished”消息,把之前所有发送的数据做个摘要,再加密一下,让服务器做个验证。意思就是告诉服务器:“后面都改用对称算法加密通信了啊,用的就是打招呼时说的AES,加密对不对还得你测一下。”
服务器也是同样的操作,发“Change Cipher Spec”和“Finished”消息,双方都验证加密解密OK,握手正式结束,后面就收发被加密的HTTP请求和响应了。
为了防止账号、密码被盗,有的时候(比如网上银行)还会使用U盾给用户颁发客户端证书,实现“双向认证”,这样会更加安全。双向认证的流程也没有太多变化,只是在“Server Hello Done”之后,“Client Key Exchange”之前,客户端要发送“Client Certificate”消息,服务器收到后也把证书链走一遍,验证客户端的身份。