前端安全

832 阅读11分钟

一、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, '&quot;')
            .replace(/'/g, '&apos;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');
}

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解码,获取用户信息,实现鉴权