跨域
CORS 跨域资源共享,服务端支持
对于简单请求,比如 GET
和 POST
,浏览器在请求时候会在头部带上 Origin
,指明请求页面的源,后端通过判断若决定响应,则再响应头加入 Access-Control-Allow-Origin
,值可以使源,也可以是 *
对于其他请求,通过叫做预检请求的机制进行验证,在请求前会先发送一个 Options
请求,询问服务器支持的类型,请求头部包含以下字段
Origin
同简单请求Access-Control-Request-Method
请求希望支持的方法Access-Control-Request-Headers
自定义头部
服务器判断后如果决定响应,则需要在头部返回以下信息
Access-Control-Allow-Headers
支持的自定义头部Access-Control-Allow-Methods
支持的方法Access-Control-Allow-Origin
同简单请求
图片探测
即通过设置 <img src='xxx' />
来实现请求,通常用来触发上报,跟踪用户
- 只能发送
GET
请求 - 无法接受消息
JSONP
实现原理,通过 <script src='xxxxx.js' />
发送请求给服务器,服务器返回的字符串中调用指定回调函数传送数据
浏览器代码
<script>
function hello(data) {
console.log(data);
}
</script>
<script src="http://127.0.0.1:3000/index.js?callback=hello"></script>
服务器代码
const http = require('http');
const url = require('url');
http.createServer(function (request, response) {
const urlParse = url.parse(request.url, true);
const callback = urlParse.query.callback
response.end(`${callback}('hello world')`);
}).listen(3000);
执行成功会输出 hello world
- JSONP同样只能执行简单的
GET
请求,但是可以带参数, - 由于拉取了可执行代码,安全性需要确定
- 确认失败比较困难
其他
iframe:打开一个 iframe
,两个页面之间通过 postMessage
进行交互
Cookie相关
http是无状态协议,cookie是管理服务器与客户端之间状态的东西
Set-Cookie
服务器端告诉客户端需要存储在客户端的cookie值,基本格式
Set-Cookie: name=xxx;Max-age=60;Secure
name=xxx
表示key和value,后面;
分隔的是参数,约定了cookie怎么存在,具体的参数有
Max-Age
: 常用的属性,表示cookie存在的时长,以秒为单位Path
: 指定可访问Cookie的目录,如设定Path=/home
,则只有/home
才能访问该值Domain
: 指定可访问该值得域名,这里的域名是指同一主机下的域名,例如我们设置了Domain=test.com
,这时候api.test.com
,www.test.com
都能访问该值HttpOnly
: 使JavaScript无法访问该值,尝试后document.cookie
无法获取该值Expires
: 设置Cookie的过期时间,这个属性感觉没有Max-Age
好用,这个你得把具体的时间计算出来,例如:Expires=Wed, 13-Jan-2021 22:23:01 GMT
Secure
: 只有在https请求时cookie才会生效SameSite
: 跨站请求时是否被发送,可以防止CSRF攻击,SameSite 取值有以下- Strict仅允许一方请求携带 Cookie,即浏览器将只发送相同站点请求的 Cookie,即当前网页 URL 与请求目标 URL 完全一致。
- Lax允许部分第三方请求携带 Cookie
- None无论是否跨站都会发送 Cookie
Cookie
请求中,用Cookie字段告诉服务器本地存储的Cookie值,在浏览器中这一步实际是浏览器做了的,这就简单得多的,就是key=value
的形式,以;
分隔
Cookie: age=222; name=yyd
注意事项
- cookie存储是有限制的,不同浏览器cookie的大小和最大存储数量不一致
Max-Age
和Expires
同时存在优先Max-Age
安全相关
由于http不具备必要的安全功能,且http请求的诸多信息都是可篡改的,所以我们需要了解不安全的地方在那儿以及应对手法
SQL注入
SQL注入是指针对Web应用使用的数据库,通过运行非常的SQL而产生的攻击
影响:
- 非法查看或篡改数据库内的数据
- 规避认证
- 执行和数据库服务器业务关联的程序等
SQL注入的作用端是在后端,但产生通常是通过前端传送给后端的数据,所以这里 前端应该对用户输入的值进行校验,后端应该对前端传送过来的值进行校验
OS命令注入
和SQL注入类似,SQL注入是攻击者执行非法的SQL语句,而OS是指攻击者执行非法的操作系统命令,达到最服务器造成攻击的目的
跨站脚本攻击( Cross-Site Scripting, XSS )
通过存在安全漏洞的Web网站注册用户的浏览器内运行非法的HTML标签或JavaScript进行的一种攻击
造成影响:
- 利用虚假输入表单片区用户个人信息,
- 利用脚本窃取用户的Cookie值,被害者在不知情的情况下,帮助攻击者发送而已请求。
- 显示伪造的文章或图片
案例: 动态生成HTML处发生,这个很常见,比如我们一个input框,需要实时显示用户输入的内容
<div id="root">
<div>111</div>
</div>
<input type="text" id="input">
<div id="preview"></div>
<script>
document.getElementById('input').onchange= (e) => {
document.getElementById('preview').innerHTML = e.target.value;
}
</script>
当我们在input中输入html的时候就会有问题
如果输入JavaScript代码会更危险,解决方法就是我们可以在输出用户的输入的时候做转义,或者检测到html字符的时候不做输出,下面提供一个html转义的方法
function htmlEscape(text) {
return text.replace(/[<>"&]/g, function (match, pos, originalText) {
switch (match) {
case "<": return "<";
case ">": return ">";
case "&": return "&";
case "\"": return """;
}
});
}
url的查询字段和hash值也是用户可以随意篡改的地方,所以在取的时候也应该进行校验
跨站点请求伪造 (Cross-Site Request Forgeries, CSRF)
攻击是指攻击者通过设置好的陷阱,强制对已完成认证的用户进行非预期的个人信息或设定信息等某些状态更新。
加入我们网站中有一个更新评论的get接口
http://example.com/msg?q=hello
攻击网站将这段代码以图片的形式放到B网站上
<img src="http://example.com/msg?q=hello" />
如果A用户在已经登录我们网站的情况下,再去访问B网站,就会在用户不知情的情况下发起一个更新评论的请求。
如果请求是post呢?这时候攻击者需要在自己的网站里整个form表单,将action
指向我们网站
<form action="http://example.com/msg" method="POST">
<input type="text" name="q">
<input type="submit" value="OK">
</form>
防御手段
- Get 请求不对数据进行修改
- Cookie 字段中加入
SameSite
(兼容性会有问题) - 服务器验证
Referer
,后台接收到请求的时候可通过请求头里的Referer
字段校验 - 验证token,服务器下发一个随机token,请求的时候每次带上这个token,比如曾经用
Laravel
框架的时候就可以在渲染时候通过csrf_token
方法获取到token
开放重定向
如我们有个url
http://example.com/login?redirect=http://example.com/home
这里意思是登录后跳转到home
这个路由,但攻击者如果通过篡改redirect就可能将用户引导至其他危险网站,同样需要我们在使用的时候进行充分的校验
HTTP 1.0、HTTP 1.1、HTTP2.0
HTTP 1.0
- 比较老的协议,浏览器与服务器只保持短暂的连接,每次请求都会重新建立连接,即每次都会经历握手挥手过程
- 解决连接复用的问题,提出了
keep-alive:connection
,但引入新的问题,队头阻塞,即使前面的请求响应未完成阻塞后面的请求
解决队头阻塞的一个方案是,部署多个域名,比如api接口部署在
api.xxx.com
,文件部署在其他域名下
HTTP 1.1
- 默认开启了长连接
- 新的缓存机制
cache-control
host
,虚拟主机在同一ip,使用host
区分- 管道机制,可以同时发起多个请求,但接收响应顺序接收,存在阻塞问题
HTTP 2.0
- 请求和响应多路复用,解决队头阻塞问题
- 首部压缩,压缩算法 + 共同维护索引
- 服务器推送
状态码
描述返回的请求结果,借助状态码,用户可以知道服务端是正常处理了请求还是出现了错误,总结几个常见的
组成
3位数字和原因短语,例如 200 OK
数字中的第一位指定了响应类别,后两位为分类
2XX
2XX的响应结果表明请求被正常处理
200 OK
请求被正常处理
204 No Content
请求被正常处理,但在返回的响应中部包含主体部分,一般在只需要从客户端往服务器发送信息,而对客户端不需要发送新信息内容时候使用
206 Partial Content
表示客户端进行了范围请求,服务器成功执行,响应报文中包含 Content-Range
指定范围的实体内容
3XX
301 Moved Permanently
永久重定向,如果保存为书签,应根据Location首部字段提示的URI重新保存。这里刚开始我以为浏览器会自动给你修改书签,事实是我想多了,修改书签只是建议,浏览器并不会自动帮你更新书签
302 Found
临时重定向,临时性质的重定向,以后还可能改动,不建议更改书签
4XX
表示客户端发生错误
400 Bad Request
请求错误,具体错误原因未知
401 Unauthorized
请求需要认证
403 Forbidden
访问权限被拒绝
偶尔会被人问到403和401的区别,401就是在需要认证未认证的时候返回,403则是已经认证,但是权限出现问题的时候返回
404 Not Found
无法找到请求的资源,也可在服务器拒绝请求但不想给出理由时返回(就是制造迷惑行为,俺是这么理解的)
5XX
服务器本身发生错误
500 Internal Server Error
服务器执行请求发生错误
503 Server Unavailable
服务器暂时处于超负载或者正在停机维护,可以通过返回 Retry-After
字段告诉客户端什么时间段重试 Retry-After
504 Gateway Timeout
超时
Storage
LocalStorage 和 SessionStorage,并不属于http,偶然看到就记一下,主要区别
- SessionStorage 独立于网页窗口存在,随窗口关闭一起清除,不会跨窗口共享
- LocalStorage 同一个域共享一份数据,只有清除才会消失
握手
TCP三次握手
网上有很多经典解释,有很多图,我这里放一张我通过抓包获得的图吧
- 客户端发送一个
SYN
标记的包,Seq
初始序列号x
,发送完成后客户端进入SYN_SEND
状态。 - 服务器返回ACK应答,同时还要发送一个
SYN
包回去。Ack = x + 1
,表示确认,Seq = y
。发送完成后服务端进入SYN_RCVD
状态。 - 客户端确认服务器收到了自己发起连接的包,同时返回
ACK
应答服务器
为什么是三次
客户端和服务端为了确认对方能正常的接收和发送
TCP四次挥手
- 客户端发起连接释放请求,设置
FIN
为1
,带上Seq = u
,客户端进入FIN-WAIT-1
- 服务器收到
FIN
后,会返回一个ACK
,并带上Ack = u + 1
, 服务器进入CLOSE-WAIT
,客户端收到后进入FIN-WAIT-2
- 服务端准备好后,发送结束连接请求,设置
FIN
为1
,带上确认号Ack = u + 1
、序号Seq = w
,进入LAST-ACK
- 客户端收到服务端结束请求,发送一个确认包,服务器收到后进入
CLOSED
,客户端会进入一个等待,等待服务端需要重传的ACK
,如果在一个固定时间内没收到,则会进入CLOSED
为什么是四次
服务端在收到结束连接请求时,可能部分数据还正在传输,所以需要一个准备阶段,只有等到准备好了,才会告诉客户端我准备好了,结束连接
客户端为什么最后需要等待
这里是为了确认客户端最后一个 ACK
到达了服务端,如果服务端没收到,则会要求重发,所以客户端需要等待
缓存
- 强缓存:浏览器不与服务器协商直接取缓存
- 协商缓存:浏览器与服务器协商取得缓存
协商缓存
主要用到http头部字段 Etag
和 Last-Modified
,每次收到一个请求时候,服务器将资源最后修改时间 Last-Modified
和根据资源计算出来的 Etag
值放到header头里面,客户端在收到这两个值后会保存这两个值、并在下次请求的时候将两个值分别放到 If-Modified-Since
和 If-None-Match
中,服务器收到后进行比对,如果都一样则返回304使得浏览器使用缓存,如果有变化则返回新资源和 200
使用协商缓存时需要设置 cache-control: no-cache
强缓存
使用字段 Cache-control
,取值如下
no-cache
缓存前需要协商no-store
禁用缓存public
允许任何用户缓存private
只允许浏览器缓存max-age
响应最大age