HTTP是一件很美的事情:一个已经存在20多年的协议,没有太大的变化。
这是Web安全系列的第二部分:第一部分是浏览器的工作方式 。正如我们在上一篇文章中看到的,浏览器使用HTTP协议与Web应用程序进行交互,这是我们深入研究此主题的主要原因。 如果用户在网站上输入信用卡信息,并且攻击者可以在到达服务器之前拦截数据,则我们可能会遇到问题。
了解HTTP的工作原理,如何保护客户端和服务器之间的通信以及协议提供哪些与安全性相关的功能是提高安全性的第一步。
但是,在讨论HTTP时,我们应始终区分语义和技术实现,因为这是HTTP的两个完全不同的方面。
他们之间的主要区别可以用一个非常简单的类比来解释:20年前,尽管他们的互动方式发生了很大变化,但人们以与现在相同的方式照顾亲戚。 我们的父母很可能会开车兜风并开车去姐姐身边,并花一些时间陪伴家人。
取而代之的是,如今,他们通常将消息发送到WhatsApp,打电话或使用Facebook上的群组,而以前这是不可能的。 这并不意味着人们或多或少地交流或关心,而仅仅是他们的互动发生了变化。
HTTP也不例外:多年来,协议的语义没有太大变化,而客户端和服务器交互的技术实现已得到优化。 如果您查看1996年的HTTP请求,它将与我们在上一篇文章中看到的请求非常相似,尽管这些数据包通过网络的方式非常不同。
复习
如我们所见,当连接到服务器的客户端发送请求并且服务器响应时,HTTP遵循请求/响应模型。
HTTP消息(请求或响应)由几个部分组成:
- “第一行”(第一行)
- 标头(请求标头)
- 正文(请求正文)
在请求中,第一行指示客户端使用的方法,他想要的资源的路径以及他将要使用的协议的版本:
GET /players/lebron-james HTTP/1.1
在这种情况下,客户端尝试通过协议版本
1.1
在
/Players/Lebron-James
获取资源(
GET
)-理解起来并不复杂。
在第一行之后,HTTP允许我们通过键值形式的标头(用冒号分隔)将元数据添加到消息中:
GET /players/lebron-james HTTP/1.1
Host: nba.com
Accept: */*
Coolness: 9000
例如,在此请求中,客户端向请求添加了3个附加标头:
Host
,
Accept
和
Coolness
。
等一下,
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/comments HTTP/1.1
Host: nba.com
Accept: */*
Coolness: 9000
Best Player Ever
我们的请求已完成:第一行(位置和协议信息),标题和正文。 请注意,主体是完全可选的,并且在大多数情况下,仅在我们要将数据发送到服务器时才使用主体,因此在上面的示例中使用了
POST
方法。
答案没有什么不同:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: private, max-age=3600
{"name": "Lebron James", "birthplace": "Akron, Ohio", ...}
响应中发送的第一个信息是它使用的协议的版本以及此响应的状态。 以下是标题,以及(如果需要)正文后面的换行符。
如前所述,该协议经过了多次修订,并且随着时间的推移,增加了新功能(新的标头,状态代码等),但是主要结构并没有太大变化(第一行,标头和主体)。 真正改变的是客户端和服务器如何交换这些消息-让我们仔细研究一下。
HTTP vs HTTPS vs H2
HTTP / 1.0
有2个重大的语义更改:
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更好 。
Https
HTTPS(HTTP安全)允许客户端和服务器通过TLS(传输层安全)(SSL(安全套接字层)的后继产品)进行安全通信。
TLS着重解决的问题非常简单,可以用一个简单的比喻来说明:您的知己在会议中午打电话给您,并要求您告诉您网上银行帐户的密码,因为它必须完成银行业务转移以确保及时支付您儿子的学费。 您必须立即举报,这一点非常重要,否则您将有可能第二天早上将孩子驱逐出学校。
现在您面临两个问题:
- 验证您是否正在与您的知己聊天,因为可能有人假装自己是她
- 加密 :传输密码,以便您的同事无法理解和写下密码
你会怎么做? 这正是HTTPS试图解决的问题。
为了验证您正在与之交谈的人,HTTPS使用公共密钥证书(公共密钥证书),它只不过是指示特定服务器身份的证书:当您通过HTTPS连接到IP地址时,该地址后面的服务器将向您显示他的证书供您证明您的身份。 回到我们的类比,您可以要求您的知己说出您的社会保险号。 验证数字正确后,您将获得更高的信任度。
但是,这并不能阻止“攻击者”找到受害者的社会保险号,偷走您的知己的智能手机并给您打电话。 我们如何验证呼叫者的身份?
与其直接要求您的伴侣写您的社会安全号码,不如打电话给您的妈妈(住在隔壁),让她去您的公寓,并确保另一半说您的社会安全号码。 由于您不认为母亲是威胁,而是依靠母亲来验证呼叫者的身份,因此可以增加信任度。
就HTTPS而言,您的母亲称为CA,是证书颁发机构的缩写:CA的工作是验证特定服务器的身份并使用其自己的数字签名颁发证书:这意味着当我连接到特定域时,我将不会收到域所有者生成的证书(即所谓的
自签名)证书 )和CA。
CA的任务是验证域的真实性并相应地颁发证书:当您“订购”证书(通常称为SSL证书,尽管当前使用TLS时,通常称为SSL证书-名称确实存在!),CA可能会打电话给您或要求更改DNS设置以确保您控制此域。 验证过程完成后,它将颁发证书,然后可以将其安装在Web服务器上。
然后,客户端(例如浏览器)将连接到您的服务器并接收此证书,以便他们可以验证其真实性:浏览器与CA具有某种“关系”,从某种意义上说,它们会跟踪CA中的受信任域列表以确保该证书是真正值得信赖的。 如果证书不是由受信任的权威机构签名的,则浏览器将为用户显示较大的信息性警告:

我们正在确保您与另一半之间的通信已完成一半:既然我们已经通过了身份验证(验证了呼叫者的身份),则需要确保我们可以安全地进行通信,而无需其他人干预。 正如我提到的,您就在会议中间,您需要写下您的在线银行密码。 您需要找到一种加密通信的方法,以便只有您和您的知己可以理解您的对话。
您可以通过在两个人之间设置一个公用密钥并使用此密钥对消息进行加密来进行此操作:例如,您可以根据结婚日期使用
“凯撒”密码选项。

如果双方(例如您和您的知己)建立了关系,这将很好地起作用,因为他们可以基于没人知道的共享内存来创建密钥。 但是,浏览器和服务器无法使用相同的机制,因为它们事先并不相互了解。
取而代之的是,使用
了Diffie-Hellman密钥交换协议的变体,
该变体可以确保在没有先验知识的情况下,各方可以建立共享的秘密密钥,而其他任何人都不能“窃取”它。 这包括
使用数学 。

一旦安装了密钥,客户端和服务器即可进行通信,而不必担心有人会截获其消息。 即使攻击者这样做,他们也将不需要共享的密钥来解密消息。
有关HTTPS和Diffie-Hellman的更多信息,我建议阅读Hartley Brody的“
HTTPS 如何保护连接 ”和“
HTTPS如何真正起作用?”。 »罗伯特·希顿(Robert Heaton)。 此外,
《改变未来的九种算法》中有精彩的一章介绍了公共密钥加密,我热烈地将其推荐给对原始算法感兴趣的计算机科学爱好者。
随处可见的Https
仍在决定是否应在网站上支持HTTPS? 对于您来说,我有个坏消息:浏览器已开始保护用户免受不支持HTTPS的网站的侵害,以“强制” Web开发人员提供完全加密的浏览功能。
遵循“
无处不在的
HTTPS ”的座右铭
,浏览器开始反对未加密的连接-Google是第一个向Web开发人员提供截止日期的浏览器提供商,宣布从Chrome 68开始(2018年7月),它将HTTP网站标记为“不安全” :
对于不使用HTTPS的网站而言,更为麻烦的是,一旦用户在网页上键入内容,“不安全”标签就会变成红色-此步骤应鼓励用户在交换数据之前三思。与不支持HTTPS的网站。
将此与具有有效证书的HTTPS站点的外观进行比较:
从理论上讲,网站不应该是安全的,但实际上它会吓跑用户-是正确的。 在H2尚未成为现实的日子里,坚持使用未加密的简单HTTP流量是很有意义的。 目前,实际上没有任何理由。 加入HTTPS Everywhere运动,帮助使Internet
成为一个更安全的冲浪场所 。
GET vs 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=1234 HTTP/1.1" 200 525 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" 404 0.002 [example-local] 172.17.0.8:9090 525 0.002 200
192.168.99.1 - [192.168.99.1] - - [29/Jul/2018:00:40:47 +0000] "GET / HTTP/1.1" 200 525 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" 393 0.004 [example-local] 172.17.0.8:9090 525 0.004 200
192.168.99.1 - [192.168.99.1] - - [29/Jul/2018:00:41:34 +0000] "PUT /users HTTP/1.1" 201 23 "http://example.local/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" 4878 0.016 [example-local] 172.17.0.8:9090 23 0.016 201
如您所见,Web服务器记录了请求路径:这意味着,如果您在URL中包含敏感数据,Web服务器将跳过它们并将它们存储在日志中的某个位置-您的敏感数据将位于纯文本,我们需要完全避免。
想象一下,攻击者可以访问您的旧日志文件之一 ,该
文件可能包含信用卡信息,用于私人服务的访问令牌等,这将是一场彻底的灾难。
Web服务器不记录HTTP标头和正文,因为存储的数据太庞大了-这就是为什么通过请求正文而不是URL发送信息通常更安全的原因。 从这里我们可以推断出
POST
(以及类似的非幂等方法)比
GET
更安全,即使它更多地取决于使用某种方法发送数据的方式,而不是一种特定的方法本质上比其他方法更安全的事实:如果您在
GET
请求的正文中包含机密信息,那么与使用
POST
相比,您不会遇到更多的问题,即使这种方法被认为是不寻常的。
我们相信HTTP标头
在本文中,我们研究了HTTP,HTTP的发展以及它的安全扩展如何结合身份验证和加密以允许客户端和服务器通过安全通道进行通信:这并不是HTTP在安全性方面必须提供的全部功能。
该翻译得到专业安全公司EDISON Software的支持,并且还在开发电子医疗验证系统 。