一、XSS
-
什么是XSS攻击
cross site script 跨站脚本攻击,是一种代码注入攻击,攻击者在目标网站注入恶意代码,当被攻击者登录网站时就会执行这些恶意代码,这些脚本可以获取cookie,session token,或者其他敏感网站信息。
xss攻击的本质是:恶意代码未经过滤,与网站正常的代码混在一起,浏览器无法识别哪些脚本是可信的,导致恶意脚本被执行。由于在用户终端执行,恶意代码能够直接获取用户信息,攻击者利用这些信息冒充用户想网站发起自己定义的请求 -
攻击类型
1、反射型
(1)攻击步骤:
a、攻击者构造出特殊的url,其中包含恶意代码
b、用户打开带有恶意代码的url时,网站服务端将恶意代码从url中取出,拼接在html
中返回给浏览器
c、浏览器接收到响应后解析执行,其中的恶意代码也被执行
d、恶意代码可以窃取用户数据并发到攻击者的网站,或者冒充用户的行为,调用目标
网站接口,执行攻击者操作
(2)、防范手段
a、设置cookie是带上HtppOnly,使得在客户端无法获取到cookie信息res.addHeader('Set-Cookie',"userid=XXX;path=/;HttpOnly")b、对url查询参数进行转义encodeURIComponent再输出到页面
app.get('/home', (req,res)=>{ res.send(encodeURIComponent(req.query.type)) })
2、DOM型XSS攻击
实际上就是前段js代码不严谨,把不可信的内容插入到页面,在使 用.innerHTML, outerHTML,appenChild等api时要格外小心,不要把不可信的数据 作为html插到页 面上
(1)、攻击步骤:
a、攻击者构造出特殊的数据,其中包含恶意代码
b、浏览器执行了恶意代码
c、恶意代码携带用户信息发送到攻击者网站,或者冒充用户行为,调用目标网站接口 执行恶意操作
(2)、防范手段
防范DOM型XSS核心是对输入的内容进行转义,对敏感特殊字符<>"'进行转义
function encodeHtml(str) {
return str.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
}
3、存储型XSS攻击
恶意脚本永久存在目标服务器上,当浏览器请求时,脚本从服务器传回并执行。存在的 根本原因仍然是没有做好过滤,前端没有做好过滤就提交到服务端,服务端没有做过滤 就存到数据库,前端从服务器请求到数据时没有做好过滤就输出。这种攻击常见于带有 用户保存信息的网站,如论坛、商品评论、贴吧等
(1)、攻击步骤:
a、攻击者将恶意代码提交到目标网站数据库中
b、用户打开目标网站时,网站服务器将恶意代码从数据库中取出,拼在html中给浏览 器
c、用户浏览器接收到用户数据并发送到攻击者网站,或者冒充用户,调用目标网站接 口执行恶意操作
(2)、防范措施:要转义!!!
a、前端提交数据给服务端之前对特殊字符转义
b、后端在存储之前要对特殊字符转义
c、前端在获取数据,拼接html,渲染页面之前,对特殊字符转义
-
除了转义之外的防护
1、CSP:只允许加载同域下的资源:服务端设置http的content-security-policy,或者在前端meta标签设置,只允许加载同域下的资源,有很多配置项<meta http-equiv="Content-Security-Policy" content="form-action 'self';">
2、设置cookie为httpOnly,无法在客户端用js获取cookie
res.addHeader('Set-Cookie',"uid=xxx;path=/;HttpOnly")
CSRF
- 什么是CSRF?
cross-site-request-forgrey:跨站请求伪造,利用用户已登录态,攻击者诱导用户进入恶意网站,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,染过后台的用户验证,达到冒充用户对被攻击网站执行恶意操作的目的 - 攻击过程
1、用户登录了网站A,并保留了登录凭证(cookie)
2、攻击者诱导用户访问了站点B
3、站点B向站点A发送恶意请求,浏览器会默认携带站点A的凭证,绕过了用户验证
4、攻击完成。 - 防御
1、判断请求的来源:header中有referer信息,判断来源是否安全
2、使用token(主流)
CSRF攻击之所以能成功,就是使用cookie,绕过了服务端的用户鉴权。那么我们就要求所有的用户请求都携带一个攻击者无法获取的token。服务器通过验证token是否正确将用户和CSRF攻击者分隔开
步骤:
a、登录成功时,服务端生成一个token,传递给用户
b、用户提交请求时携带这个token
c、服务器验证token是否正确 - 禁止第三方网站携带cookie, sameSite Cookie属性,存在兼容性问题
三、HTTP协议
一、页面输入url到页面渲染,发生了什么?
- 用户输入www.baidu.com
- 浏览器通过DNS服务器,将url解析为IP地址
- 和ip地址建立tcp连接,就是三次握手,发送http请求
- 服务器收到请求,查库、读文件等,返回http响应
- 浏览器解析html为dom
- 解析css为css-tree
- dom+css生成render-tree
- 加载js文件
- 执行js
二、http报文格式
- 请求报文格式
请求行:方法 URL 协议/版本号=> POST /form/save HTTP/1.1
请求头:accept: /, referer: localhost:8080,connetction: keep-alive
空行
请求体:name=wky&age=18 - 响应报文格式
状态行 :协议/版本 状态码 状态码说明
响应头:
Content-Type: text/html;chartset=utf-8
Set-Cookie: name=XXX;path=/;HttpOnly
Access-Control-Allow-Origin: localhost: 8080,
Access-Control-Allow-methods: GET,POST,DELETE,PUT,
Access-Control-Max-Age: 8640,
Access-Control-Allow-Headers: CORS-XSS,CORS-XSS-TEST
空行
响应体 ...
三、GET和POST的区别
- post相对get更安全一点,因为get请求参数都暴露在url中,且会被浏览器保存历史记录
- post通过request body可以传输更多的数据
- url有长度限制,会影响get请求
- get请求能被浏览器缓存,而post不能
四、常见的状态码
- 2XX 成功
200 ok,表示从客户端发送的请求在服务端被正确处理 - 3XX 重定向
301 永久性重定向
302 临时重定向
304 not modified 资源未改变,取缓存 - 4XX 客户端错误
400 bad request,请求报文存在语法错误
401
403 forbidden,对资源请求的访问被服务器拒绝
404 not found,资源不存在 - 5XX 服务器错误
500 initernal server error,服务器在执行请求发生了错误
三、cors跨域配置
-
Access-Control-Allow-origin: 192.168.1.110:8080,允许某一个域请求资源,简单请求设置这个即可,复杂请求还要设置预请求头部
-
Access-Control-Allow-Headers: XSS-TEST-1,XSS-TEST-2
-
Access-control-Allow-method: GET,POST,PUT,DELTE,允许某些方法请求,默认只有GET和POST
-
Access-Controll-Max-Age: 606024,设置这个,预请求在这个时间间隔不会发送OPTION预请求
3.2 跨域的其他方案
-
jsonp
-
webpack-dev-server
四、浏览器缓存
- 首次加载,http请求,sever正常返回
返回响应头加上强缓存的说明 - 强缓存
1、expires:过期时间,日期
2、cache-control:max-age=30000 ,优先级比expires更高
3、这两个header都是后端告诉浏览器,这个文件,多少时间内不会过期,比如1h,1h内再次请求这个文件,强缓存命中,请求不发出,直接使用本地的缓存为文件 状态码 200 from memery cache - 协商缓存
1、一个小时后再次发起请求,强缓存已经失效,使用协商缓存
2、浏览器不会直接请求文件,而是先问后端这个文件是否被修改过,请求头带上if-modified-since: 日期,值为上次请求相同资源,服务端header里传过来的last-modify。服务器收到请求头带有if-modified-since,则与被请求资源最后修改的时间作对比,如果二者相等,说明文件没有修改过,使用缓存,返回状态码304 not modified
3、如果二者不等,说明被修改过,重新加载文件,状态码 200 ok
4、etag优先级更高,etag相当于文件指纹,通常是有文件索引节、大小和最后修改时间进行hash计算后得到的。如果文件内容不变,指纹不变。浏览器请求头带上if-none-match请求头,服务器收到请求后,发现请求头有if-none-match,则与etag做比较,确定返回200还是304
五、connection:keep-alive是干什么的?
1、在早期的http1.0中,每次http请求都要创建一个tcp连接,通过三次握手创建TCP连接,这个过程需要消耗资源和时间的。在http头里面加入connection:keep-alive,请求响应完成后不用关闭,下次还要复用这个连接。
2、http2.0中实现了多路复用,同域下所有通信都在单个连接上完成
六、http2.0有哪些新特性
- 信道复用
1、在http1.1中可以设置connect:keep-alive使得tcp连接不关闭,复用连接。如果想并发多个请求,必须使用多个tcp连接,浏览器为了控制资源,会对单个域名tcp连接请求的限制,chrome是6个。
2、http2.0中,同域下,所有通信都在单个tcp连接上完成 - 分帧传输
帧:http2数据通信的最小单位消息。http2采用二进制格式传输数据,而http1采用文本格式,二进制解析起来更高效 - server push,服务端主动推送消息
服务端可以在发送页面时主动推送其他资源,而不用等到浏览器解析到响应位置,发起请求再响应。例如服务端可以主动把js和css文件推送给客户端,而不用等到客户端解析html时再发送请求 - 头部压缩
http1中请求和响应头中会重复携带冗长的头部信息,给网络带来额外负担。http2.0中,对于相同的数据,不再通过每次请求和响应发送。只发送差异数据,减少头部信息量
七、为什么有了http还要https
https是http+SSL,是安全版的http,因为http协议的数据都是明文进行传输的,所以对一些敏感信息的传输就很不安全,https就是为了解决http的不安全而生的
八、https是如何保证安全的
- 对称加密
通信双方都是用同一个秘钥进行加密解密,叫做对称加密。 - 非对称加密
1、公钥+私钥=密钥对
2、用公钥加密的数据只有对应的私钥才能解密,公钥可以下发给客户端,私钥保存在服务端
3、服务器下发公钥给客户端,对应私钥保存在服务端
4、客户端使用公钥加密数据传送给服务端,服务端使用对应私钥进行解密 - 中间人的问题
问题:客户端跟服务器之间存在一个中间人,这个中间人把服务器下发的公钥换成自己的公钥,就可以轻松解密客户端数据
解决:数字证书,验证消息摘要是否被篡改过
四、用户鉴权
常见鉴权方式:session/cookie、token
session/cookie
- 原理
1、服务器在接收客户端首次访问时在服务器端生成一个session,这个session记录着用户信息,对外暴露sid,(签名:通过秘钥对sid进行签名处理,加密),例如session={'xxxxxxx':{userInfo: {}}},通常保存在Redis中。
2、响应头中种下这个cookie信息,res.setHeader('Set-Cookie','sid=xxxxxxx')
3、浏览器接收到请求响应,会解析响应头,把sid保存在cookie中,浏览器下次请求时,请求头会带上该域下的cookie信息
4、服务端接受客户端请求解析出sid,然后根据这个sid去redis中找对应session,判断该请求是否合法
5、路由守卫中间件,通常把校验逻辑写成一个中间件,需要鉴权的路由,执行这个中间件
token
- 原理
1、用户登陆成功,创建一个token,这个token通过JWT签名秘钥加密,里面包含用户信息。返回给客户端
2、客户端接收到这个token,这本地存起来,localstorage等。以后每次请求带上这个token
3、服务端通过token解码,获取用户信息,实现鉴权