前几章没什么好记录的,就没写了。后面加了一些安全相关的内容。
4 HTTP状态码
4.1 状态码告知从服务器端返回的请求结果
| 状态码 | 类别 | 原因短语 |
|---|---|---|
| 1XX | Informational(信息性状态码) | 接收的请求正在处理 |
| 2XX | Success(成功状态码) | 请求正常处理完毕 |
| 3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
| 4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 |
| 5XX | Server Error(服务器错误状态码) | 服务器处理请求出错 |
4.2 2XX 成功
200OK204Not Content206Partial Content回应范围请求,包含Content-Range指定范围的内容。
4.3 3XX 重定向
301Moved Permanently永久重定向到了Location 首部字段提示的 URI302Found临时性重定向。303See Other临时使用GET请求访问另一URI。304Not Modified包含If-Match,If-Modified- Since,If-None-Match,If-Range,If-Unmodified-Since 中任一首部的回应。307Temporary Redirect临时重定向。POST重定向,好像没啥人用。
4.4 4XX 客户端错误
400Bad Request请求报文中存在语法错误,浏览器会像 200 OK 一样对待该状态码。401Unauthorized需要认证信息。另外若已请求过,则表示用户认证失败。403Forbidden拒绝访问。404Not Found上无法找到请求的资源。
4.5 5XX 服务器错误
500Internal Server Error执行请求时发生了错误。503Service Unavailable服务器暂时处于超负载或正在进行停机维护。
5 与HTTP协作的Web服务器
6 HTTP首部
6.1 HTTP首部字段
6.2 HTTP/1.1 通用首部字段
6.2.1 Cache-Control
格式
Cache-Control: private, max-age=0, no-cache
缓存请求指令
| 指令 | 参数 | 说明 |
|---|---|---|
| no-cache | 强制向源服务器再次验证 | |
| no-store | 不缓存请求或响应的任何内容 | |
| max-age = [ 秒] | 必需 | 响应的最大Age值 |
| max-stale( = [ 秒]) | 可省略 | 接收已过期的响应 |
| min-fresh = [ 秒] | 必需 | 期望在指定时间内的响应仍有效 |
| no-transform | 代理不可更改媒体类型 | |
| only-if-cached | 从缓存获取资源 | |
| cache-extension | 新指令标记(token) |
缓存响应指令
| 指令 | 参数 | 说明 |
|---|---|---|
| public | 无 | 可向任意方提供响应的缓存 |
| private | 可省略 | 仅向特定用户返回响应 |
| no-cache | 可省略 | 缓存前必须先确认其有效性 |
| no-store | 无 | 不缓存请求或响应的任何内容 |
| no-transform | 无 | 代理不可更改媒体类型 |
| must-revalidate | 无 | 可缓存但必须再向源服务器进行确认 |
| proxy-revalidate | 无 | 要求中间缓存服务器对缓存的响应有效性再进行确认 |
| max-age=[秒] | 必需 | 响应的最大Age值 |
| s-maxage=[秒] | 必需 | 公共缓存服务器响应的最大Age值 |
| cache-extension | - | 新指令标记(token) |
no-cache 指令
Cache-Control: no-cache
客户端请求中使用,是为了防止从缓存服务器中返回过期的资源。
Cache-Control: no-cache=Location
服务器返回的响应中,如果指定了参数值,表示缓存服务器不能使用缓存。
no-store 指令
Cache-Control: no-store
该指令规定缓存服务器不能在本地存储请求或者响应信息。
max-age 指令
Cache-Control: max-age=604800(单位:秒)
6.3 请求首部字段
6.3.1 Host
虚拟主机运行在同一个 IP 上,因此使用首部字段 Host 加以区分。
Host: www.hackr.jp
6.3.2 If-Match
只有当 If-Match 的字段值跟 ETag 值匹配一致时,服务器才会接受请求。
6.4 响应首部字段
6.4.1 Age
Age: 600
6.5 为Cookie服务的首部字段
6.5.1 Set-Cookie
Set-Cookie: status=enable; expires=Tue, 05 Jul 2011 07:26:31
当服务器准备开始管理客户端的状态时,会事先告知各种信息。 Set-Cookie字段属性:
- NAME=VALUE 赋予 Cookie 的名称和其值(必需项)
- expires=DATE Cookie 的有效期(若不明确指定则默认为浏览器关闭前为止)
- path=PATH 将服务器上的文件目录作为Cookie的适用对象(若不指定则默认为文档所在的文件目录)
- domain=域名 作为 Cookie 适用对象的域名 (若不指定则默认为创建 Cookie的服务器的域名)
- Secure 仅在 HTTPS 安全通信时才会发送 Cookie
- HttpOnly 加以限制,使 Cookie 不能被 JavaScript 脚本访问
6.5.2 Cookie
Cookie: status=enable
客户端请求中包含从服务器接收到的 Cookie,告知服务器想获得状态管理支持。
7 HTTPS
7.1 通信加密
通过和 SSL(Secure Socket Layer,安全套接层)或 TLS(Transport Layer Security,安全层传输协议)的组合使用,加密 HTTP 的通信内容。
7.2 HTTP+ 加密 + 认证 + 完整性保护=HTTPS
HTTPS 是身披 SSL 外壳的 HTTP。
7.2.1 HTTPS CA证书及加密通信流程
因为公钥加密处理速度慢,所以采用混合加密,先使用公钥加密传输共享密钥,之后通过共享密钥加密通信。
9 基于 HTTP 的功能追加协议
9.3 WebSocket
为了实现 WebSocket 通信,在 HTTP 连接建立之后,需要完成一次“握手”(Handshaking)的步骤。
- 握手·请求
用 HTTP 的 Upgrade 首部字段,告知服务器通信协议发生改变,以达到握手的目的。
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Origin: example.com Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13
Sec-WebSocket-Key 字段内记录着握手过程中必不可少的键值。 Sec-WebSocket-Protocol 字段内记录使用的子协议。
- 握手·响应
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= Sec-WebSocket-Protocol: chat
Sec-WebSocket-Accept 的字段值是由握手请求中的 Sec-WebSocket-Key 的字段值生成的。
成功握手确认 WebSocket 连接之后,不再使用 HTTP 的数据帧,而采用 WebSocket 独立的数据帧。
9.4 HTTP/2.0
HTTP/2是HTTP协议自1999年HTTP1.1发布后的首个更新,主要基于SPDY协议。
9.4.1 SPDY协议
SPDY是Speedy的昵音,意为“更快”。它是Google开发的基于TCP协议的应用层协议。目标是优化HTTP协议的性能,通过压缩、多路复用和优先级等技术,缩短网页的加载时间并提高安全性。SPDY协议的核心思想是尽量减少TCP连接数。SPDY是对HTTP协议的增强。
9.4.2 HTTP1.X的缺点
- HTTP/1.0一次只允许在一个TCP连接上发起一个请求,HTTP/1.1使用的流水线技术也只能部分处理请求并发,仍然会存在队列头阻塞问题,因此客户端在需要发起多次请求时,通常会采用建立多连接来减少延迟。
- 单向请求,只能由客户端发起。
- 报文首部信息冗余量大。
- 数据未压缩。
9.4.2.1 HTTP/1.1队头阻塞
http1.x采用长连接(Connection:keep-alive),可以在一个TCP请求上,发送多个http请求。
- 管道化:完全串行执行,请求->响应->请求->响应...,后一个请求必须在前一个响应之后发送。导致阻塞。
- 非管道化:问题更多,基本不用。
解决办法:浏览器一个域名采用6-8个TCP连接,并发HTTP请求。
9.4.3 HTTP 2.0特点
9.4.3.1 二进制分帧
由字符串传输改为二进制传输。
为了保证HTTP不受影响,那就需要在应用层(HTTP2.0)和传输层(TCP or UDP)之间增加一个二进制分帧层。在二进制分帧层上,HTTP2.0会将所有传输的信息分为更小的消息和帧,并采用二进制格式编码,其中HTTP1.x的首部信息会被封装到Headers帧,而Request Body则封装到Data帧。
9.4.3.2 首部压缩
使用了HPACK(HTTP2头部压缩算法)压缩减小大小,并对出现过的内容进行缓存,减少重复传输。
9.4.3.3 多路复用
因为浏览器对同一域名下的请求数量有限制,所以可能会导致阻塞排队。
而 HTTP/2 引入二进制数据帧和流的概念,其中帧对数据进行顺序标识,这样浏览器收到数据之后,就可以按照序列对数据进行合并,而不会出现合并后数据错乱的情况。同样是因为有了序列,服务器就可以并行的传输数据。
HTTP/2 对同一域名下所有请求都是基于流,也就是说同一域名不管访问多少文件,也只建立一路连接。同样Apache的最大连接数为300,因为有了这个新特性,最大的并发就可以提升到300,比原来提升了6倍。
9.4.3.4 请求优先级
把HTTP消息分为很多独立帧之后,就可以通过优化这些帧的交错和传输顺序进一步优化性能。
9.4.3.5 服务器推送
服务器可以对一个客户端请求发送多个响应。服务器向客户端推送资源无需客户端明确的请求。
11 Web 的攻击技术
XSS 跨站脚本攻击
(Cross-Site Scripting,XSS),XSS 的原理是恶意攻击者往 Web 页面里插入恶意可执行网页脚本代码。
非持久型 XSS
也叫反射型 XSS 漏洞,一般通过在URL是添加恶意代码参数攻击。
如何预防:
- 尽量不要从
URL,document.referrer,document.forms等这种 DOM API 中获取数据直接渲染。 - 尽量不要使用
eval,new Function(),document.write(),document.writeln(),window.setInterval(),window.setTimeout(),innerHTML,document.creteElement()等可执行字符串的方法。 - 前端渲染的时候对任何的字段都需要做 escape 转义编码。
持久型 XSS
持久型 XSS 漏洞,也被称为存储型 XSS 漏洞,一般存在于 Form 表单提交等交互功能,黑客利用的 XSS 漏洞,将内容经正常功能提交进入数据库持久保存,当前端页面获得后端从数据库中读出的注入代码时,恰好将其渲染执行。 如何预防:
- 后端在入库前将所有的字段统一进行转义处理。
- 后端在输出给前端数据统一进行转义处理。
- 前端在渲染页面 DOM 的时候任何字段都需要做转义处理。
基于字符集的 XSS
通过其他字符集来绕过转义处理。 如何预防:
- 记住指定
<meta charset="utf-8"> - XML 中不仅要指定字符集为 utf-8,而且标签要闭合
基于 Flash 的跨站 XSS
AS 脚本可以接受用户输入并操作 cookie,不过FLASH已死。。。
未经验证的跳转 XSS
有一些场景是后端需要对一个传进来的待跳转的 URL 参数进行一个 302 跳转,可能其中会带有一些用户的敏感(cookie)信息。
CSRF 跨站请求伪造
CSRF(Cross-Site Request Forgery),跨站请求伪造攻击。
CSRF 原理
CSRF 预防
如何预防:
- 提交验证码。
- 验证HTTP Referer字段。该字段记录了HTTP请求的来源地址。
- token验证。在 HTTP 请求中以參数的形式添加一个服务端产生的随机token,并在服务器端来验证。
- 在 HTTP 头中自己定义属性添加token并验证。
SQL 注入
SQL注入原理
SQL注入攻击,往往是没有对用户输入进行过滤,比如Form表单,导致服务端使用参数拼接成SQL语句后,执行了意料之外的逻辑。
SQL注入预防
- 对输入内容进行转义及过滤处理。
- 所有的查询语句建议使用数据库提供的参数化查询接口。
- 严格限制Web应用的数据库的操作权限。
- 服务端不要返回过于详细的错误信息。
命令行注入
原理和SQL注入差不多。
DDoS 攻击
DDoS 又叫分布式拒绝服务,全称 Distributed Denial of Service,其原理就是利用大量的请求造成资源过载,导致服务不可用。DDos 攻击从层次上可分为网络层攻击与应用层攻击,从攻击手法上可分为快型流量攻击与慢型流量攻击
网络层 DDoS
SYN Flood 攻击
SYN flood 攻击主要利用了 TCP 三次握手过程,TCP 三次握手过程是要建立连接的双方发送 SYN,SYN + ACK,ACK 数据包,而当攻击方随意构造源 IP 去发送 SYN 包时,服务器返回的 SYN + ACK 就不能得到应答(因为 IP 是随意构造的),此时服务器就会尝试重新发送,并且会有至少 30s 的等待时间,导致资源饱和服务不可用,此攻击属于慢型 DDoS 攻击。
ACK Flood 攻击
ACK Flood 攻击是在 TCP 连接建立之后,所有的数据传输 TCP 报文都是带有 ACK 标志位的,主机在接收到一个带有 ACK 标志位的数据包的时候,需要检查该数据包所表示的连接四元组是否存在,如果存在则检查该数据包所表示的状态是否合法,然后再向应用层传递该数据包。如果在检查中发现该数据包不合法,例如该数据包所指向的目的端口在本机并未开放,则主机操作系统协议栈会回应 RST 包告诉对方此端口不存在。
UDP Flood 攻击
UDP flood 攻击是由于 UDP 是一种无连接的协议,因此攻击者可以伪造大量的源 IP 地址去发送 UDP 包,此种攻击属于大流量攻击。正常应用情况下,UDP 包双向流量会基本相等,因此发起这种攻击的攻击者在消耗对方资源的时候也在消耗自己的资源。
ICMP Flood 攻击
ICMP Flood 攻击属于大流量攻击,其原理就是不断发送不正常的 ICMP 包(所谓不正常就是 ICMP 包内容很大),导致目标带宽被占用,但其本身资源也会被消耗。目前很多服务器都是禁 ping 的(在防火墙在可以屏蔽 ICMP 包),因此这种攻击方式已经落伍。
网络层 DDoS 防御
网络层的 DDoS 攻击究其本质其实是无法防御的,我们能做得就是不断优化服务本身部署的网络架构,以及提升网络带宽。当然,还是做好以下几件事也是有助于缓解网络层 DDoS 攻击的冲击:
- 网络架构上做好优化,采用负载均衡分流。
- 确保服务器的系统文件是最新的版本,并及时更新系统补丁。
- 添加抗 DDos 设备,进行流量清洗。
- 限制同时打开的 SYN 半连接数目,缩短 SYN 半连接的 Timeout 时间。
- 限制单 IP 请求频率。
- 防火墙等防护设置禁止 ICMP 包等。
- 严格限制对外开放的服务器的向外访问。
- 运行端口映射程序或端口扫描程序,要认真检查特权端口和非特权端口。
- 关闭不必要的服务。
- 认真检查网络设备和主机/服务器系统的日志。只要日志出现漏洞或是时间变更,那这台机器就可能遭到了攻击。
- 限制在防火墙外与网络文件共享。这样会给黑客截取系统文件的机会,主机的信息暴露给黑客,无疑是给了对方入侵的机会。
- 加钱堆机器。。
- 报警。。
应用层 DDoS
应用层 DDoS 攻击不是发生在网络层,是发生在 TCP 建立握手成功之后。应用层攻击千变万化,目的就是在网络应用曾耗尽你的带宽。
CC 攻击
CC 攻击的原理,就是针对消耗资源比较大的页面不断发起不正常的请求,导致资源耗尽。
DNS Flood
DNS Flood 攻击采用的方法是向被攻击的服务器发送大量不存在的域名解析请求,由于DNS服务器会往上一层层去查找,负载过大导致正常DNS域名解析超时。
HTTP 慢速连接攻击
针对 HTTP 协议,先建立起 HTTP 连接,设置一个较大的 Conetnt-Length,每次只发送很少的字节,让服务器一直以为 HTTP 头部没有传输完成,这样连接一多就很快会出现连接耗尽。
应用层 DDoS 防御
- 判断 User-Agent 字段(不可靠,因为可以随意构造)
- 针对 IP + cookie,限制访问频率(由于 cookie 可以更改,IP 可以使用代理,或者肉鸡,也不可靠)
- 关闭服务器最大连接数等,合理配置中间件,缓解 DDoS 攻击。
- 请求中添加验证码,比如请求中有数据库操作的时候。
- 编写代码时,尽量实现优化,并合理使用缓存技术,减少数据库的读取操作。
- 加钱堆机器。。
- 报警。。
流量劫持
DNS 劫持
DNS 劫持,也叫做域名劫持,把域名解析到了错误的ipi地址。一般是由于小运营商出问题,或者电脑中毒。
HTTP 劫持
HTTP 劫持主要是当用户访问某个站点的时候会经过运营商网络,而不法运营商和黑产勾结能够截获 HTTP 请求返回内容,并且能够篡改内容,然后再返回给用户。可以使用https或者设置 Content-Security-Policy 来部分避免,如:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
参考资料
- 《图解HTTP》
- 常见 Web 安全攻防总结