2017-09-23更新 添加HTTP状态码,HTTPS
HTTP
HTTP协议在TCP/IP协议栈的位置如下图所示:
由于HTTP报文是面向文本的,因此报文中的每一个字段都是一些ASCII码串,但各个字段的长度是不确定的。
请求报文格式
如上图所示:请求报文分为四个部分:
- 请求行:包含请求方法,URL和HTTP版本号,中间用空格分隔;
- 请求头: 首部字段名: + 空格 + value;
- 空行:请求头之后必须有空行;
- 请求数据:POST请求数据,格式为key:value形式。GET不行,它的数据放在URL中;
响应报文格式
如上图所示:响应报文分为四个部分:
- 响应行:包含HTTP版本,状态码和短语,中间用空格分隔;
- 响应头: 首部字段名: + 空格 + value;
- 空行:响应头之后必须有空行;
- 实体主体:响应数据,HTML文本,图片等二进制数据
POST和GET区别
首先引入一个副作用的概念,副作用指当你发送完一个请求以后,网站上的资源状态没有发生修改,即认为这个请求是无副作用的。比如注册用户这个请求是有副作用的,获取用户详情可以认为是无副作用的。
再引入一个幂等性的概念,幂等是说,一个请求原封不动的发送N次和M次(N不等于M,N和M都大于1)服务器上资源的状态最终是一致的。比如发贴是非幂等的,重放10次发贴请求会创建10个帖子。但修改帖子内容是幂等的,一个修改请求重放无论多少次,帖子最终状态都是一致的。唠叨了这么多,回过头来,何时用 PUT POST GET DELETE:GET:无副作用,幂等PUT:副作用,幂等POST:副作用,非幂等DELETE:副作用,幂等
为了进一步区分这些请求方式的应用场景,我们再引入一个技术特性,request body,就是大家广为流传的 “POST 请求传输数据量比较大“ 这一说法的来源。POST/PUT 请求可以通过传递 request body 来发送大量的数据,而 GET/DELETE 不能。
请求动作 | 有无副作用 | 是否幂等 | 数据发送方式 |
---|---|---|---|
GET | 无副作用 | 幂等 | 不可带 Request Body |
PUT | 副作用 | 幂等 | 可以带 Request Body |
POST | 副作用 | 非幂等 | 可以带 Request Body |
DELETE | 副作用 | 幂等 | 不可带 Request Body |
区别:
- GET参数通过URL传递,POST参数放在Request body中。
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET请求会被浏览器主动缓存,而POST不会,除非手动设置。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求在URL中传送的参数是有长度限制的,而POST没有。限制主要来自浏览器和服务器,各个标准不同。IE为2083个字符。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。(相对安全)
HTTP首部
参见我的博客HTTP首部字段解析
HTTP状态码
1xx消息
这一类型的状态码,代表请求已被接受,需要继续处理。这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束。由于HTTP/1.0协议中没有定义任何1xx状态码,所以除非在某些试验条件下,服务器禁止向此类客户端发送1xx响应。这些状态码代表的响应都是信息性的,标示客户应该采取的其他行动。
状态码 | 英文名称 | 中文名称 | 说明 |
---|---|---|---|
1xx | 临时响应 | 表示临时响应并需要请求者继续执行操作的状态代码。 | |
100 | Continue | 继续 | 请求者应当继续提出请求。服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。 |
101 | Switching Protocols | 切换协议 | 请求者已要求服务器切换协议,服务器已确认并准备切换。 |
2xx成功
这一类型的状态码,代表请求已成功被服务器接收、理解、并接受
状态码 | 英文名称 | 中文名称 | 说明 |
---|---|---|---|
2xx | 成功 | 表示成功处理了请求的状态代码。 | |
200 | OK | 成功 | 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。 |
201 | Created | 已创建 | 请求成功并且服务器创建了新的资源。 |
202 | Accepted | 已接受 | 服务器已接受请求,但尚未处理。 |
203 | Non-Authoritative Information | 非授权信息 | 服务器已成功处理了请求,但返回的信息可能来自另一来源。 |
204 | No Content | 无内容 | 服务器成功处理了请求,但没有返回任何内容。 |
205 | Reset Content | 重置内容 | 服务器成功处理了请求,但没有返回任何内容。 |
206 | Partial Content | 部分内容 | 服务器成功处理了部分 GET 请求。 |
3xx重定向
这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的Location域中指明。当且仅当后续的请求所使用的方法是GET或者HEAD时,用户浏览器才可以在没有用户介入的情况下自动提交所需要的后续请求。客户端应当自动监测无限循环重定向(例如:A→B→C→……→A或A→A),因为这会导致服务器和客户端大量不必要的资源消耗。按照HTTP/1.0版规范的建议,浏览器不应自动访问超过5次的重定向。
状态码 | 英文名称 | 中文名称 | 说明 |
---|---|---|---|
3xx | 重定向 | 表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。代码 说明 | |
300 | Multiple Choices | 多种选择 | 针对请求,服务器可执行多种操作。服务器可根据请求者选择一项操作,或提供操作列表供请求者选择。 |
301 | Moved Permanently | 永久移动 | 请求的网页已永久移动到新位置。服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。 |
302 | Found(原始描述短语为“Moved Temporarily”) | 临时移动 | 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。 |
303 | See Other | 查看其他位置 | 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。 |
304 | Not Modified | 未修改 | 自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。 |
305 | Use Proxy | 使用代理 | 请求者只能使用代理访问请求的网页。如果服务器返回此响应,还表示请求者应使用代理。 |
307 | Temporary Redirect | 临时重定向 | 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。 |
4xx客户端错误
这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。除非响应的是一个HEAD请求,否则服务器就应该返回一个解释当前错误状况的实体,以及这是临时的还是永久性的状况。这些状态码适用于任何请求方法。浏览器应当向用户显示任何包含在此类错误响应中的实体内容。如果错误发生时客户端正在传送数据,那么使用TCP的服务器实现应当仔细确保在关闭客户端与服务器之间的连接之前,客户端已经收到了包含错误信息的数据包。如果客户端在收到错误信息后继续向服务器发送数据,服务器的TCP栈将向客户端发送一个重置数据包,以清除该客户端所有还未识别的输入缓冲,以免这些数据被服务器上的应用程序读取并干扰后者。
状态码 | 英文名称 | 中文名称 | 说明 |
---|---|---|---|
4xx | 请求错误 | 这些状态代码表示请求可能出错,妨碍了服务器的处理。 | |
400 | Bad Request | 错误请求 | 服务器不理解请求的语法。 |
401 | Unauthorized | 未授权 | 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。 |
403 | Forbidden | 禁止 | 服务器拒绝请求。 |
404 | Not Found | 未找到 | 服务器找不到请求的网页。 |
405 | Method Not Allowed | 方法禁用 | 禁用请求中指定的方法。 |
406 | Not Acceptable | 不接受 | 无法使用请求的内容特性响应请求的网页。 |
407 | Proxy Authentication Required | 需要代理授权 | 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。 |
408 | Request Timeout | 请求超时 | 服务器等候请求时发生超时。 |
409 | Conflict | 冲突 | 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。 |
410 | Gone | 已删除 | 如果请求的资源已永久删除,服务器就会返回此响应。 |
411 | Length Required | 需要有效长度 | 服务器不接受不含有效内容长度标头字段的请求。 |
412 | Precondition Failed | 未满足前提条件 | 服务器未满足请求者在请求中设置的其中一个前提条件。 |
413 | Request Entity Too Large | 请求实体过大 | 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。 |
414 | Request-URI Too Long | 请求的 URI 过长 | 请求的 URI(通常为网址)过长,服务器无法处理。 |
415 | Unsupported Media Type | 不支持的媒体类型 | 请求的格式不受请求页面的支持。 |
416 | Requested Range Not Satisfiable | 请求范围不符合要求 | 如果页面无法提供请求的范围,则服务器会返回此状态代码。 |
417 | Expectation Failed | 未满足期望值 | 服务器未满足”期望”请求标头字段的要求。 |
5xx服务器错误
表示服务器无法完成明显有效的请求。这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。除非这是一个HEAD请求,否则服务器应当包含一个解释当前错误状态以及这个状况是临时的还是永久的解释信息实体。浏览器应当向用户展示任何在当前响应中被包含的实体。这些状态码适用于任何响应方法。
状态码 | 英文名称 | 中文名称 | 说明 |
---|---|---|---|
5xx | 服务器错误 | 这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。 | |
500 | Internal Server Error | 服务器内部错误 | 服务器遇到错误,无法完成请求。 |
501 | Not Implemented | 尚未实施 | 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。 |
502 | Bad Gateway | 错误网关 | 服务器作为网关或代理,从上游服务器收到无效响应。 |
503 | Service Unavailable | 服务不可用 | 服务器目前无法使用(由于超载或停机维护),通常这只是暂时状态。 |
504 | Gateway Timeout | 网关超时 | 服务器作为网关或代理,但是没有及时从上游服务器收到请求。 |
505 | HTTP Version Not Supported | HTTP 版本不受支持 | 服务器不支持请求中所用的 HTTP 协议版本。 |
HTTPS
HTTPS协议在HTTP协议基础之上添加了SSL(Secure Sockets Layer)/TLS(Transport Layer Security)层。
不使用SSL/TLS的HTTP通信,就是不加密的通信。所有信息明文传播,带来了三大风险。
- 窃听风险(eavesdropping):第三方可以获知通信内容。
- 篡改风险(tampering):第三方可以修改通信内容。
- 冒充风险(pretending):第三方可以冒充他人身份参与通信。
SSL/TLS协议是为了解决这三大风险而设计的,希望达到:
- 所有信息都是加密传播,第三方无法窃听。
- 具有校验机制,一旦被篡改,通信双方会立刻发现。
- 配备身份证书,防止身份被冒充。
HTTP协议和HTTPS协议区别
- HTTPS协议需要到CA申请证书。
- HTTP是超文本传输协议,信息是明文传输;HTTPS 则是具有安全性的SSL加密传输协议。
- HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- HTTP的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP协议安全。
基本运行过程
SSL/TLS协议的基本思路是采用公钥加密法,客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。
但是,这里有两个问题。
(1)如何保证公钥不被篡改?
解决方法:将公钥放在数字证书中。只要证书是可信的,公钥就是可信的。
(2)公钥加密计算量太大,如何减少耗用的时间?
解决方法:每一次会话(session),客户端和服务器端都生成一个”会话密钥”(session key),用它来加密信息。由于”会话密钥”是对称加密,所以运算速度非常快,而服务器公钥只用于加密”会话密钥”本身,这样就减少了加密运算的消耗时间。
因此,SSL/TLS协议的基本过程是这样的:
- 客户端向服务器端索要并验证公钥。
- 双方协商生成”会话密钥”。
- 双方采用”会话密钥”进行加密通信。
上面过程的前两步,又称为”握手阶段”(handshake)。
握手阶段详细过程
握手阶段图解:
<1>客户端发出请求(ClientHello)1>
首先,客户端(通常是浏览器)先向服务器发出加密通信的请求,这被叫做ClientHello请求。
在这一步,客户端主要向服务器提供以下信息。
- 支持的协议版本,比如TLS 1.0版。
- 一个客户端生成的随机数,稍后用于生成”会话密钥”。
- 支持的加密方法,比如RSA公钥加密。
- 支持的压缩方法。
这里需要注意的是,客户端发送的信息之中不包括服务器的域名。也就是说,理论上服务器只能包含一个网站,否则会分不清应该向客户端提供哪一个网站的数字证书。这就是为什么通常一台服务器只能有一张数字证书的原因。对于虚拟主机的用户来说,这当然很不方便。2006年,TLS协议加入了一个Server Name Indication扩展,允许客户端向服务器提供它所请求的域名。
<2>服务器回应(SeverHello)2>
服务器收到客户端请求后,向客户端发出回应,这叫做SeverHello。服务器的回应包含以下内容。
- 确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。
- 一个服务器生成的随机数,稍后用于生成”会话密钥”。
- 确认使用的加密方法,比如RSA公钥加密。
- 服务器证书。
除了上面这些信息,如果服务器需要确认客户端的身份,就会再包含一项请求,要求客户端提供”客户端证书”。比如,金融机构往往只允许认证客户连入自己的网络,就会向正式客户提供USB密钥,里面就包含了一张客户端证书。
<3>客户端回应3>
客户端收到服务器回应以后,首先验证服务器证书。如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。
如果证书没有问题,客户端就会从证书中取出服务器的公钥。然后,向服务器发送下面三项信息。
- 一个随机数。该随机数用服务器公钥加密,防止被窃听。
- 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
- 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验。
上面第一项的随机数,是整个握手阶段出现的第三个随机数,又称”Premaster key”。有了它以后,客户端和服务器就同时有了三个随机数,接着双方就用事先商定的加密方法,各自生成本次会话所用的同一把”会话密钥”。
至于为什么一定要用三个随机数,来生成”会话密钥”,dog250解释得很好:
“不管是客户端还是服务器,都需要随机数,这样生成的密钥才不会每次都一样。由于SSL协议中证书是静态的,因此十分有必要引入一种随机因素来保证协商出来的密钥的随机性。
对于RSA密钥交换算法来说,”Premaster key”本身就是一个随机数,再加上hello消息中的随机,三个随机数通过一个密钥导出器最终导出一个对称密钥。
“Premaster”的存在在于SSL协议不信任每个主机都能产生完全随机的随机数,如果随机数不随机,那么”Premaster secret”就有可能被猜出来,那么仅使用”Premaster secret”作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和服务器加上”Premaster secret”三个随机数一同生成的密钥就不容易被猜出了,一个伪随机可能完全不随机,可是是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一。”
此外,如果前一步,服务器要求客户端证书,客户端会在这一步发送证书及相关信息。
<4>服务器的最后回应4>
服务器收到客户端的第三个随机数”Premaster key”之后,计算生成本次会话所用的”会话密钥”。然后,向客户端最后发送下面信息。
- 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
- 服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供客户端校验。
至此,整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用”会话密钥”加密内容。
总结
握手阶段
第一步,爱丽丝给出协议版本号、一个客户端生成的随机数(Client random),以及客户端支持的加密方>法。
第二步,鲍勃确认双方使用的加密方法,并给出数字证书、以及一个服务器生成的随机数(Server random)。
第三步,爱丽丝确认数字证书有效,然后生成一个新的随机数(Premaster secret),并使用数字证书中的公钥,加密这个随机数,发给鲍勃。
第四步,鲍勃使用自己的私钥,获取爱丽丝发来的随机数(即Premaster secret)。
第五步,爱丽丝和鲍勃根据约定的加密方法,使用前面的三个随机数,生成”会话密钥”(session key),用来加密接下来的整个会话过程。
握手阶段重点
- 生成会话密钥一共需要三个随机数。
- 握手之后的会话使用”会话密钥”加密(对称加密),服务器的公钥和私钥只用于加密和解密”会话密钥”(其实是加密、解密生成“会话密钥”的随机数),无其他作用。
- 服务器公钥放在服务器的数字证书之中。
安全性保证
Premaster secret保证会话密钥安全性
整个握手阶段都不加密(也没法加密),都是明文的。因此,如果有人窃听通信,他可以知道双方选择的加密方法,以及三个随机数中的两个。整个通话的安全,只取决于第三个随机数(Premaster secret)能不能被破解。第三个随机数是经过公钥加密的,保证了信息的安全。
虽然理论上,只要服务器的公钥足够长(比如2048位),那么Premaster secret可以保证不被破解。但是为了足够安全,我们可以考虑把握手阶段的算法从默认的RSA算法,改为 Diffie-Hellman算法(简称DH算法)。采用DH算法后,Premaster secret不需要传递,双方只要交换各自的参数,就可以算出这个随机数。
数字证书安全性
通过公钥加密的数据,只能通过私钥解开。这个叫非对称加密。
通过私钥加密的数据,只能通过公钥解开。这个叫数字签名。
受信任的第三方保护服务器公钥,防止被伪造和篡改。其中使用数字签名和摘要,保证其不被伪造和篡改。