HTTP构建于 TCP/IP 协议之上,默认端口号 80,是无连接状态的。
状态码
状态码 | 描述 |
---|---|
200 | OK, 客户端请求成功 |
302 | Moved Temporaily, 请求重定向 |
304 | Not Modified, 文件未修改, 可使用缓存文件 |
400 | Bad Request, 客户端请求有语法错误, 服务端无法理解 |
401 | Unauthorized, 请求未经授权 |
403 | Forbidden, 服务器收到请求, 但是拒绝提供服务 |
404 | Not Found, 请求的资源不存在 |
500 | Internal Server Error, 服务器发生不可预期的错误 |
503 | Service Unavailable, 服务器当前不能处理客户端请求, 一段时间后可能会恢复 |
持久连接
HTTP 协议采用“请求-应答”模式,当使用普通模式,即非 Keep-Alive 模式时,每个请求/应答客户和服务器都要新建一个连接,完成之后立即断开连接(HTTP协议为无连接的协议);当使用 Keep-Alive 模式(又称持久连接、连接重用)时,Keep-Alive 功能使客户端到服务器端的连接持续有效。
在 HTTP 1.1 版本中,默认情况下所有连接都被保持,如果加入 Connection: close 才关闭。
- HTTP Keep-Alive 简单说就是保持当前的TCP连接,避免了重新建立连接。
- HTTP 长连接不可能一直保持,例如 Keep-Alive: timeout=5, max=100,表示这个TCP通道可以保持5秒,max=100,表示这个长连接最多接收100次请求就断开。
- HTTP 是一个无状态协议,这意味着每个请求都是独立的,Keep-Alive没能改变这个结果。另外,Keep-Alive也不能保证客户端和服务器之间的连接一定是活跃的,在HTTP1.1版本中也如此。唯一能保证的就是当连接被关闭时能得到一个通知,所以不应该让程序依赖于Keep-Alive的保持连接特性,否则会有意想不到的后果。
- 使用长连接之后,客户端、服务端怎么知道本次传输结束呢?两部分:1. 判断传输数据是否达到了Content-Length 指示的大小;2. 动态生成的文件没有 Content-Length ,它是分块传输(chunked),这时候就要根据 chunked 编码来判断,chunked 编码的数据在最后有一个空 chunked 块,表明本次传输数据结束。
HTTP Pipelining管线化
默认情况下 HTTP 协议中每个传输层连接只能承载一个 HTTP 请求和响应,浏览器会在收到上一个请求的响应之后,再发送下一个请求。
在使用持久连接的情况下,某个连接上消息的传递类似于 请求1 -> 响应1 -> 请求2 -> 响应2 -> 请求3 -> 响应3
。
HTTP Pipelining(管线化)是将多个 HTTP 请求整批提交的技术,在传送过程中不需等待服务端的回应。
使用 HTTP Pipelining 技术之后,某个连接上的消息变成了类似这样 请求1 -> 请求2 -> 请求3 -> 响应1 -> 响应2 -> 响应3。
- 管线化机制通过持久连接完成,仅 HTTP/1.1 支持此技术(HTTP/1.0不支持)
- 只有 GET 和 HEAD 请求可以进行管线化,而 POST 则有所限制
- 管线化不会影响响应到来的顺序,响应返回的顺序并未改变。
- HTTP /1.1 要求服务器端支持管线化,但并不要求服务器端也对响应进行管线化处理,只是要求对于管线化的请求不失败即可。
- 由于上面提到的服务器端问题,开启管线化很可能并不会带来大幅度的性能提升,而且很多服务器端和代理程序对管线化的支持并不好。
会话跟踪
会话:客户端打开与服务器的连接发出请求到服务器响应客户端请求的全过程称之为会话。
会话跟踪:指的是对同一个用户对服务器的连续的请求和接受响应的监视。
会话跟踪常用方法:
- URL重写
URL重写的技术就是在URL结尾添加一个附加数据以标识该会话,把会话ID通过URL的信息传递过去,以便在服务器端进行识别不同的用户。 - 隐藏表单域
将会话ID添加到HTML表单元素中提交到服务器,此表单元素并不在客户端显示。 - Cookie
Cookie是Web服务器发送给客户端的一小段信息,客户端请求时可以读取该信息发送到服务器端。
客户端可以采用两种方式来保存这个Cookie对象,一种方式是保存在客户端内存中,称为临时Cookie,浏览器关闭后这个Cookie对象将消失。另外一种方式是保存在客户机的磁盘上,称为永久Cookie。以后客户端只要访问该网站,就会将这个Cookie再次发送到服务器上,前提是这个Cookie在有效期内,这样就实现了对客户的跟踪。 - Session
服务器端会创建一个session对象,产生一个sessionID来标识这个session对象。然后将这个sessionID放入到Cookie中发送到客户端,下一次访问时,sessionID会发送到服务器,在服务器端进行识别不同的用户。
跨站攻击 CSRF/XSRF
CSRF(Cross-site request forgery,XSRF,跨站请求伪造):伪造请求,冒充用户在站内的正常操作。
CSRF攻击是源于WEB的隐式身份验证机制,WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。
事例
银行网站A,它以GET请求来完成银行转账的操作,如:http://www.mybank.com/Transfer.php?toBankId=11&money=1000
危险网站B,它里面有一段HTML的代码如下:<img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>
首先,你登录了银行网站A,然后访问危险网站B,这时你会发现你的银行账户少了1000块……
为什么会这样呢?原因是银行网站A违反了HTTP规范,使用GET请求更新资源。在访问危险网站B的之前,你已经登录了银行网站A,而B中的<img>
以GET的方式请求第三方资源(这里的第三方就是指银行网站了,原本这是一个合法的请求,但这里被不法分子利用了),所以你的浏览器会带上你的银行网站A的Cookie发出Get请求,去获取资源“http://www.mybank.com/Transfer.php?toBankId=11&money=1000”,结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作……
更多事例:参见 浅谈CSRF
CSRF防范
- 关键请求只接受 POST 请求。
- 验证码。
CSRF攻击的过程,往往是在用户不知情的情况下构造网络请求。所以如果使用验证码,那么每次操作都需要用户进行互动。 - 检测 Referer
通过检查Referer的值,就可以判断这个请求是合法的还是非法的,但是问题出在服务器不是任何时候都能接受到Referer的值,所以 Referer Check 一般用于监控 CSRF 攻击的发生,而不用来抵御攻击。 - Token
目前主流的做法是使用 Token 抵御 CSRF 攻击。CSRF攻击要成功的条件在于攻击者能够预测所有的参数从而构造出合法的请求。所以根据不可预测性原则,我们可以对参数进行加密从而防止CSRF攻击。另一个更通用的做法是保持原有参数不变,另外添加一个参数Token,其值是随机的。这样攻击者因为不知道Token而无法构造出合法的请求进行攻击。
Token 使用原则:足够随机、一次性、保密性。
跨站脚本攻击 XSS
XSS(Cross Site Scripting,跨站脚本攻击)是注入攻击的一种。其特点是不对服务器端造成任何伤害,而是通过一些正常的站内交互途径,例如发布评论,提交含有 JavaScript 的内容文本。这时服务器端如果没有过滤或转义掉这些脚本,作为内容发布到了页面上,其他用户访问这个页面的时候就会运行这些脚本。
XSS 是实现 CSRF 的诸多途径中的一条,一般习惯上把通过 XSS 来实现的 CSRF 称为 XSRF。
防御 XSS 攻击
理论上,所有可输入的地方没有对输入数据进行处理的话,都会存在XSS漏洞,漏洞的危害取决于攻击代码的威力,攻击代码也不局限于script。防御 XSS 攻击最简单直接的方法,就是过滤用户的输入。