简介HTTP是一个美丽的东西:一个已经存在20多年而没有太大变化的协议。正如我们在上一篇文章中看到的,浏览器通过HTTP协议与Web应用程序进行交互,这是我们深入研究该主题的主要原因。如果用户在网站上输入他们的信用卡信息,黑客可以在数据到达服务器之前拦截数据,我们肯定会遇到麻烦。了解HTTP的工作原理、我们如何保护客户端和服务器之间的通信以及协议提供的安全相关功能是改善安全状况的第一步。然而,在讨论HTTP时,我们应该始终区分语义和技术实现,因为它们是HTTP工作方式的两个截然不同的方面。两者之间的主要区别可以用一个非常简单的类比来解释:20年前,人们和现在一样关心他们所爱的人,尽管他们互动的方式发生了巨大变化。我们的父母可能会开车去他们姐姐家,只是为了赶上家人。相反,现在更常见的是在WhatsApp上留言、打电话或使用Facebook群组,这在以前是不可能的。并不是人们或多或少地在交流或关心,而是他们交流的方式发生了变化。HTTP也不例外:协议背后的语义没有太大变化,而客户端和服务器之间通信的技术实现多年来一直在优化。如果您查看1996年的HTTP请求,它看起来与我们在上一篇文章中看到的请求非常相似,尽管这些数据包在网络中传输的方式非常不同。概述如前所述,HTTP遵循请求/响应模型,其中连接到服务器的客户端发出请求,服务器响应它。一个HTTP消息(请求或响应)由多个部分组成:请求行请求头请求正文部分:请求行用于描述请求类型、要访问的资源以及使用的HTTP版本。GET/players/lebron-jamesHTTP/1.1GET表示请求类型为GET,/players/lebron-james为要访问的资源,该行后半部分表示使用HTTP1.1版本。第二部分:请求头,紧跟在请求行之后的部分,用来表示服务器要使用的附加字母。GET/players/lebron-jamesHTTP/1.1Host:nba.comAccept:*/*Coolness:9000例如,在这个请求中,客户端向请求附加了3个额外的标头:Host、Accept和Coolness。等等,酷是什么?标头不必使用特定的保留名称,但一般建议依赖HTTP规范标准化的名称:越是偏离标准,在交流中就越不会被对方理解。例如,Cache-Control是一个标头,用于定义响应是否可缓存:大多数代理和反向代理完全按照HTTP规范理解它。如果您将Cache-Control标头重命名为Awesome-Cache-Control,代理将不再知道如何缓存响应,因为它们不是按照您刚刚提出的规范构建的。然而,有时在消息中包含“自定义”标头可能是有意义的,因为您可能希望添加实际上不属于HTTP规范的元数据:服务器可能决定在其响应中包含技术信息,以便客户端可以同时执行请求并获取有关回复的服务器状态的重要信息:...X-Cpu-Usage:40%X-Memory-Available:1%...使用自定义标头时,始终向它们添加一个键这样它们就不会与将来可能成为标准的其他标头发生冲突:从历史上看,这一直很有效,直到每个人都开始使用“非标准”X前缀,这反过来又成为常态。X-Forwarded-For和X-Forwarded-Proto标头是负载均衡器和代理广泛使用和理解的自定义标头的示例,即使它们不是HTTP标准的一部分。如果您需要添加自己的自定义标头,现在通常使用自动生成的前缀,例如Acme-Custom-Header或A-Custom-Header。在标头之后,请求可能包含一个正文,它与标头之间用空行分隔:POST/players/lebron-james/commentsHTTP/1.1Host:nba.comAccept:*/*Coolness:9000BestPlayerEver我们的请求已完成:第一行(位置和协议信息),请求头和请求体。请注意,请求主体是完全可选的,在大多数情况下,它仅在我们要向服务器发送数据时使用——这就是为什么上面的示例使用POST。响应没有太大区别:HTTP/1.1200OKContent-Type:application/jsonCache-Control:private,max-age=3600{"name":"LebronJames","birthplace":"Akron,Ohio",...}响应发布的一条信息是它使用的协议版本和响应的状态。请求标头也是如此,如果需要,在文本后加一个换行符。如前所述,该协议已经过多次修订,并且随着时间的推移添加了一些功能(新的标头、状态代码等),但底层结构并没有太大变化(请求行、请求标头和Word)。真正改变的是客户端和服务器如何交换这些消息——让我们仔细看看。HTTPvsHTTPSvsH2HTTP经历了两个相当大的语义变化:HTTP/1.0和HTTP/1.1。那么,“HTTPS和HTTP2在哪里?”HTTPS和HTTP2(缩写为H2)更像是一项技术变革,因为它们引入了通过Internet传递消息的新方法,而不会严重影响协议的语义。HTTPS是HTTP的“安全”扩展,它涉及在客户端和服务器之间建立一个公共机密,确保我们与正确的一方通信,并对使用公共机密交换的消息进行加密(稍后将详细介绍)。HTTPS的目标是提高协议HTTP的安全性,而H2的目标是让它更快。H2使用二进制消息代替纯文本,支持多路复用,使用HPACK算法压缩头部……长话短说,H2是对HTTP/1.1的性能改进。网站所有者不愿意切换到HTTPS,因为它涉及客户端和服务器之间的额外往返(如上所述,需要在双方之间建立相互秘密),减慢用户体验:默认使用H2加密,他们没有任何借口,因为多路复用和服务器推送等特性使其性能优于普通HTTP/1.1。HTTPSHTTPS的目标是允许客户端和服务器通过TLS(传输层安全性)安全地通信,TLS是SSL(安全套接字层)的后继者。TLS针对的问题相当简单,可以打个简单的比喻:你的另一半在中午打电话给你,你正在开会,要你告诉他们你网上银行账户的密码,因为他们需要执行银行转账以确保按时支付您儿子的教育费用。现在告诉他们很重要,否则您的孩子第二天早上可能会被拒之门外。你们现在面临两个挑战:身份验证:确保您真的在与您的另一半交谈,因为其他人有可能假装他们是加密的:在您的同事不理解和记录密码的情况下进行通信这正是HTTPS试图解决的问题。为了验证您正在与谁通话,HTTPS使用公钥证书,这些证书只是声明特定服务器背后的身份的证书:当您通过HTTPS连接到IP地址时,该地址背后的服务器将向您出示其证书以进行验证它的身份。回到我们的类比,可能只是你要求你的另一半拼出他们的社会安全号码。一旦验证了号码的正确性,您就会获得更高级别的信任。然而,这并不能阻止黑客了解受害者的社会安全号码、窃取您伴侣的智能手机并给您打电话。我们如何验证来电者的身份?与其让你的另一半拼出他们的社会安全号码,不如打电话给你妈妈(恰好住在你隔壁),让她来你的公寓,确保你的另一半拼出他们的社会保险号码。这增加了额外的信任度,因为您不认为您的母亲是威胁,并且依靠她来验证呼叫者的身份。在HTTPS术语中,你妈叫CA,CertificateAuthority的缩写:CA的工作是验证特定服务器背后的身份,并颁发带有自己数字签名的证书:这意味着,当我连接到时对于特定的域,我不提供由域所有者生成的证书(称为自签名证书),而是由CA颁发的。当局的工作是确保他们验证域名背后的身份并相应地颁发证书:当您“订购”证书(通常称为SSL证书,即使现在使用TLS)时,当局可能会打电话给某人或要求您更改DNS设置以确认您可以控制相关域。验证过程完成后,它将颁发一个证书,然后您可以将其安装在您的Web服务器上。像浏览器这样的客户端将连接到您的服务器并获得此证书,以便他们可以验证它看起来是真实的:浏览器与CA有某种“关系”,因为它们跟踪受信任的CA列表。为了验证证书是否真的值得信赖。如果证书不是由受信任的机构签署的,浏览器将向用户显示信息警告:保护您和您重要的其他人之间的通信已完成一半:现在我们已经处理了身份验证(调用者的身份验证),我们需要确保我们可以安全地进行通信,而不会在此过程中被其他人窃听。正如我提到的,您正在开会,需要拼出您的网上银行密码。你需要找到一种方法来加密你的通信,这样只有你和你的伙伴才能理解你们的谈话。为此,您可以在双方之间建立共享密钥,并使用该密钥加密消息:例如,您可能决定根据婚礼日期使用凯撒密码的变体。如果双方都处于稳定的关系中(例如您和您的灵魂伴侣),这会很有效,因为他们可以根据别人不知道的共享内存创建密钥。但是,浏览器和服务器不能使用相同的机制,因为它们事先并不知道彼此。相反,Diffie-Hellman密钥交换协议的一种变体可确保事先已知的任何一方都无法建立共享秘密,并且没有其他人可以“嗅探”它。这需要一点数学知识,留给读者作为练习。一旦密钥被建立,客户端和服务器就可以进行通信而不用担心有人拦截他们的消息。即使黑客这样做了,他们也没有解密消息所需的公钥。无处不在的HTTPS还在争论是否应该在您的网站上支持HTTPS?我没有好消息:浏览器已经开始让用户远离不支持HTTPS的网站,以“强制”网络开发人员提供完全加密的浏览体验。在“HTTPSEverywhere”的口号背后,浏览器开始反对未加密的连接——谷歌宣布从Chrome68(2018年7月)开始将HTTP站点标记为“不安全”:对于不使用HTTPS的站点更令人担忧的是,“不安全”一旦用户在页面上键入任何内容,“安全”标签就会变成红色——此举应该鼓励用户在与不支持HTTPS的网站交换数据之前三思而后行。将此与在HTTPS上运行并配备有效证书的网站的外观进行比较:理论上,网站不一定安全,但实际上,这会吓跑用户-这是理所当然的。当H2不流行时,坚持使用未加密的HTTP通信是有意义的,而今天也没有理由这样做。GET和POST正如我们之前看到的,一个HTTP请求以一个特殊的请求行开始:首先,客户端告诉服务器它正在使用什么动词来执行请求:常见的HTTP动词包括GET、POST、PUT和DELETE,但是可以继续使用不常见(但仍然是标准)的动词,例如TRACE、OPTIONS或HEAD。从理论上讲,没有一种方法比另一种方法更安全;实际上,事情并没有那么简单。GET请求通常没有主体,因此参数包含在URL中(例如www.example.com/articles?article_id=1),而POST请求通常用于发送(“发布”)包含的数据。另一个区别是这些动词带来的副作用:GET是一个幂等动词,这意味着无论您发送多少请求,都不会改变Web服务器的状态。相比之下,POST不是幂等的:对于您发送的每个请求,您可能会更改服务器的状态(例如,考虑发布新的付款-现在您可能明白为什么网站要求您在执行操作时不要刷新页面交易)。幂等性:指一次请求和多次请求资源应该有相同的副作用,即一次访问和多次访问都会对这个资源带来相同的变化。为了说明这些方法之间的重要区别,我们需要看一下您可能已经熟悉的Web服务器日志:192.168.99.1-[192.168.99.1]--[29/Jul/2018:00:39:47+0000]"GET/?token=1234HTTP/1.1"200525"-""Mozilla/5.0(X11;Linuxx86_64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/65.0.3325.181Safari/537.36"4040.002[示例-本地]172.17.0.8:90905250.002200192.168.99.1-[192.168.99.1]--[29/Jul/2018:00:40:47+0000]"GET/HTTP/1.1"200525"-""Mozilla/5.0(X11;Linuxx86_64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/65.0.3325.181Safari/537.36"3930.004[example-local]172.17.0.8:90905250.004200192.168.99.1--[192.168.99.0[192.168.9ul]-[192.168.9ul-0]:41:34+0000]"PUT/usersHTTP/1.1"20123"http://example.local/""Mozilla/5.0(X11;Linuxx86_64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/65.0.3325.181Safari/537.36"48780.016[example-local]172.17.0.8:9090230.016201如您所见,Web服务器记录了请求路径:这意味着,如果您在URL中包含敏感数据,那么它将被泄露d由Web服务器保存并保存在日志中的某处-您的密钥将采用明文形式,我们绝对需要避免这种情况。假设黑客获得了您的一个旧日志文件的访问权限,其中可能包含信用卡信息、私人服务的访问令牌等等:这将是一场彻头彻尾的灾难。Web服务器不记录HTTP标头或正文,因为要保存的数据太大-这就是为什么通过请求正文而不是URL发送信息通常更安全。由此我们可以得出结论,POST(以及类似的非幂等方法)比GET更安全,即使它更多地是关于在使用特定动词时如何发送数据而不是该特定动词本身比其他动词更安全:如果你将sensitive信息包含在GET请求的正文中,然后你不会比使用POST有更多的问题,即使这种方法被认为是不寻常的。我们信任HTTP标头在本文中,我们将了解HTTP、它的演变以及它的安全扩展如何集成身份验证和加密以允许客户端和服务器通过安全通道进行通信:这并不是HTTP在安全方面提供的全部。正如我们将在下一篇文章中看到的,HTTP安全标头提供了一种改善应用程序安全状况的方法,下一篇文章将专门介绍如何利用它们。
