关于前端:深入08-前端安全

32次阅读

共计 11195 个字符,预计需要花费 28 分钟才能阅读完成。

导航

[[深刻 01] 执行上下文](https://juejin.im/post/684490…
[[深刻 02] 原型链](https://juejin.im/post/684490…
[[深刻 03] 继承](https://juejin.im/post/684490…
[[深刻 04] 事件循环](https://juejin.im/post/684490…
[[深刻 05] 柯里化 偏函数 函数记忆](https://juejin.im/post/684490…
[[深刻 06] 隐式转换 和 运算符](https://juejin.im/post/684490…
[[深刻 07] 浏览器缓存机制(http 缓存机制)](https://juejin.im/post/684490…
[[深刻 08] 前端平安](https://juejin.im/post/684490…
[[深刻 09] 深浅拷贝](https://juejin.im/post/684490…
[[深刻 10] Debounce Throttle](https://juejin.im/post/684490…
[[深刻 11] 前端路由](https://juejin.im/post/684490…
[[深刻 12] 前端模块化](https://juejin.im/post/684490…
[[深刻 13] 观察者模式 公布订阅模式 双向数据绑定](https://juejin.im/post/684490…
[[深刻 14] canvas](https://juejin.im/post/684490…
[[深刻 15] webSocket](https://juejin.im/post/684490…
[[深刻 16] webpack](https://juejin.im/post/684490…
[[深刻 17] http 和 https](https://juejin.im/post/684490…
[[深刻 18] CSS-interview](https://juejin.im/post/684490…
[[深刻 19] 手写 Promise](https://juejin.im/post/684490…
[[深刻 20] 手写函数](https://juejin.im/post/684490…

[[react] Hooks](https://juejin.im/post/684490…

[[部署 01] Nginx](https://juejin.im/post/684490…
[[部署 02] Docker 部署 vue 我的项目](https://juejin.im/post/684490…
[[部署 03] gitlab-CI](https://juejin.im/post/684490…

[[源码 -webpack01- 前置常识] AST 形象语法树](https://juejin.im/post/684490…
[[源码 -webpack02- 前置常识] Tapable](https://juejin.im/post/684490…
[[源码 -webpack03] 手写 webpack – compiler 简略编译流程](https://juejin.im/post/684490…
[[源码] Redux React-Redux01](https://juejin.im/post/684490…
[[源码] axios ](https://juejin.im/post/684490…
[[源码] vuex ](https://juejin.im/post/684490…
[[源码 -vue01] data 响应式 和 初始化渲染 ](https://juejin.im/post/684490…
[[源码 -vue02] computed 响应式 – 初始化,拜访,更新过程 ](https://juejin.im/post/684490…

XSS

  • XSS (Cross Site Script) 跨站脚本攻打
  • Cross Site Script 本来是缩写为 CSS,为了辨别层叠样式表 css,改写为 XSS
  • 原理:XSS 攻打是指攻击者在网站上注入歹意的客户端代码,通过 <font color=red> 歹意脚本 </font> 对客服端网页进行篡改,从而在用户浏览网页时,对用户浏览器就行管制,或者获取用户隐衷数据一种攻击方式
  • 歹意脚本:次要指 <font color=red>javascrip 代码 </font>,有时也指 <font color=red>html</font> 和 <font color=red>flash</font>
  • 攻击方式:有多种,独特的特色是:窃取用户的隐衷数据
  • 攻打类型:能够分为三类,<font color=red> 反射型(非长久型)</font>,<font color=red> 贮存型(长久型)</font>,<font color=red> 基于 DOM</font>
  • 危害:

    • 利用虚伪的输出表单,骗取用户的个人信息
    • 利用脚本获取用户的 cookie
    • 显示伪造的图片和文章

反射型(非长久型)XSS 攻打

  • 反射型 XSS 只是简略地把用户输出的数据“反射”给浏览器,这种攻击方式往往须要攻击者诱使用户点击一个歹意链接,或者提交一个表单,或者进入一个歹意网站时,注入脚本进入被攻击者的网站。

贮存型(长久型)XSS 攻打

  • 存储型 XSS 会把用户输出的数据 “ 存储 ” 在服务器端,当浏览器申请数据时,脚本从服务器上传回并执行。这种 XSS 攻打具备很强的稳定性。

基于 DOM 的 XSS 攻打

  • 基于 DOM 的 XSS 攻打是指通过歹意脚本批改页面的 DOM 构造,是纯正产生在客户端的攻打。

进攻 XSS 攻打

  • <font color=red> 设置 httpOnly 阻止通过 script 脚本获取 cookie</font>

    • Document.cookie 属性XMLHttpRequest 对象Request API
    • XMLHttpRequest 获取 cookie

      • 通过 xhr.getResponseHeader(‘Set-Cookie’) // null,不能获取 cookie
      • 通过 xhr.getAllResponseHeader()获取所有的 simple response header,并不包含 Set-Cookie 字段
      • 留神:这两种办法都只能获取 simple response heade,而不能获取 Set-Cookie 字段
      • <font color=red> 上面会详解介绍 XMLHttpRequest</font>
  • 过滤查看:

    • 对 input,textares,form 表单等做特殊符号的过滤查看
    • HtmlEncode:某些状况下,不能对用户数据进行严格过滤,须要对标签进行转换
    • JavaScriptEncode
    
    (1) HtmlEncode:对 html 标签进行转换
    < -------------------------- &lt
    > -------------------------- &gt
    & -------------------------- &amp
    '' ------------------------- &quot
    空格 ----------------------- &nbsp
    
    
    
    (2) JavascriptEncode:对 js 一些特殊符号进行转码
    "------------------------ \"
    \n ----------------------- \\n
    \r ----------------------- \\r
    

CSRF

  • CSRF(Cross Site Request Forgery) 跨站申请伪造 forgeries:伪造品的意思
  • <font color=red>CSRF 是一种劫持受信赖用户向服务器发送非预期申请的攻击方式 </font>
  • 原理:

    • 次要是通过获取用户在指标网站的 cookie,骗取指标网站的服务器的信赖,在用户曾经登录指标站的前提下,拜访到了攻击者的钓鱼网站,攻击者间接通过 url 调用指标站的接口,伪造用户的行为进行攻打,通常这个行为用户是不知情的。
    • <font color=red> 即获取了 cookie,就能够做很多事件:比方以你的名义发送邮件、发信息、盗取账号、购买商品、虚构货币转账等等 </font>
    案例:CSRF 攻打的思维:(外围 2 和 3)1、用户浏览并登录信赖网站(如:淘宝)2、登录胜利后在浏览器产生信息存储(如:cookie)3、用户在没有登出淘宝的状况下,拜访危险网站 
    // 留神:如果该 cookie 在没有设置过期工夫或者为 null,默认是会话工夫 session-cookie,敞开浏览器后 cookie 会被革除
    // Expires,Max-Age 能够设置 cookie 的过期工夫
    // 所以这里强调了是没有登出的状况,就有 cookie 被获取的危险
    // 如果 cookie 设置了具体的过期工夫,有效期内都可能被获取
    4、危险网站中存在恶意代码,代码为发送一个歹意申请(如:购买商品 / 余额转账)// 该申请,携带刚刚在浏览器产生的信息(cookie),进行歹意申请
    5、淘宝验证申请为非法申请(辨别不出是否是该用户发送)// 用 HTTP 中的 header 头中的 Refer 来预防
    // refer 能够查看申请源,只有非法的申请起源服务器才予以响应
    6、达到了歹意指标

预防 CSRF 攻打

  • <font color=red> 验证码:</font> 被认为是反抗 CSRF 攻打最简洁无效的进攻办法

    • CSRF 往往是在用户不知情的状况下构建了网络申请,而验证码会强制用户必须与利用进行交互能力实现最终的申请
    • 留神:出于用户思考,不能给网站的所有操作都加上验证码,所以验证码只能作为进攻 CSRF 的辅助伎俩
  • <font color=red>Referer 查看 </font>

    • HTTP 中有 Refer 字段,示意申请起源地址,通过 Refer 能够查看申请是否来自非法的源,服务器只对非法的源予以响应
    • 2021/4/ 7 更正 => referer 查看,而不是 refer,留神单词拼写
    • 2021/6/21 更正 => refererReferer
  • <font color=red>token</font>

    • CSRF 次要就是获取 cookie,所以要进攻的话,就须要在申请中退出攻击者不能伪造的信息,并且该信息不能保留在 cookie 中
    • 能够在 HTTP 申请中以参数的模式退出一个随机产生的 token,并在服务器端建设一个拦截器来验证这个 token,如果申请中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻打而回绝该申请。

温习

cookie

  • cookie 是服务器保留在浏览器的一小段文本信息,大小不超过 4KB,每次申请都会携带 cookie
  • cookie 次要用来分辨两个申请知否来自同一个浏览器,和存储一个状态信息:如用户偏好色彩,字体大小等
  • 浏览器能够设置不承受 cookie,也能够设置不向浏览器发送 cookie
  • window.navigator.cookieEnabled 返回一个布尔值,示意浏览器是否关上 cookie 性能
  • document.cookie 返回以后网页的 cookie
  • 单个域名设置的 cookie 不应该超过 30 个,大小不超过 4KB
  • <font color=red> 共享 cookie 的条件:域名和端口必须一样,不要求协定雷同 </font>
  • <font color=red>cookie 的产生:cookie 由 HTTP 协定生成,也次要是供 HTTP 协定应用 </font>

HTTP 回应:cookie 的生成

  • 生成 cookie:服务器通过设置 HTTP 回应头信息中,Set-Cookie 字段来保留 cookie
  • HTTP 回应头信息中,能够蕴含 多个 Set-Cookie 字段
  • 除了 cookie 的值,Set-Cookie 还能够附加cookie 的属性,能够蕴含多个属性,没有秩序要求
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
// Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly  多个属性,没有秩序要求

[page content]

服务器如何批改曾经存在的 cookie

  • 必须满足四个条件:cookie 的 <font color=red>key,domain,path,secure</font> 都匹配
  • 只有有一个属性不同,都会生成全新的 cookie

    Set-Cookie: key1=value1; domain=example.com; path=/blog
    Set-Cookie: key1=value2; domain=example.com; path=/
    
    // 下面因为 path 不一样,就设置了一个全新的 cookie
    
    // 下次发动申请时,会同时发送两个 cookie
    // 发动申请时,发送的 cookie => Cookie: key1=value1; key1=value2
    // 留神:两个 cookie 同名,然而越准确的 cookie 排在越后面

删除一个现存 cookie 的惟一办法

  • 设置 Expires 属性为一个过期的工夫

HTTP 申请:cookie 的发送

  • 浏览器在向服务器发送 HTTP 申请时,每个申请都会携带上 cookie

    • (即浏览器把之前服务器保留在浏览器上的 cookie 再发回服务器)
    • <font color=red> 发送时应用 Cookie 字段 </font>
    • <font color=red> 生成时应用 Set-Cookie 字段 </font>
  • <font color=red>Cookie 字段能够蕴含多个 cookie,应用 ; 号宰割 </font>

    GET /sample_page.html HTTP/1.1
    Host: www.example.org
    Cookie: yummy_cookie=choco; tasty_cookie=strawberry

服务器收到浏览器发来的 cookie 时,有两点无奈晓得

  • Cookie 的各种属性:Expires,Max-Age,Domain,Path,Secure,HttpOnly
  • 哪个域名设置的 cookie,一级域名设置的,还是二级域名设置的

Cookie 的属性

Expires,Max-Age

  • Expires 属性:指定一个具体的过期工夫,UTC 格局

    • 能够应用 Date.prototype.toUTCString() 进行格局转换
    • 如果不设置 Expires 属性,或者设置 null,该 cookie 就是 session-cookie,只在会话工夫内无效,即敞开浏览器窗口,以后 session 完结,cookie 就会被删除
  • Max-Age 属性:从当初开始 cookie 存在的秒数。60*60*24*365 一年
  • 同时存在 Expires 和 Max-Age 时,Max-Age 优先

Domain,Path

  • Domain:指定浏览器收回 HTTP 申请时,哪些域名要附带这个 Cookie

    • 如果没有指定该属性,将其设置为 URL 的一级域名
  • Path:指定浏览器收回 HTTP 申请时,哪些门路要附带这个 cookie

    • 只有浏览器发现,Path 属性是 HTTP 申请门路的结尾一部分,就会在头信息中携带这个 cookie

Secure,HttpOnly

  • Secure:指定只有在加密协议 HTTPS 下,能力将这个 cookie 发送到服务器
  • HttpOnly:指定该 cookie,无奈通过脚本拿到

    • <font color=red>Document.cookie 属性,XMLHttpRequest 对象,Request API 都拿不到该 cookie</font>
    • Document.cookie 读写 cookie

      • Document.cookie 读取:读取全副
      • Document.cookie 写入:一次只能写入一个,写入不是笼罩,而是增加
      • Document.cookie 的读写差别与 HTTPT 通信格局无关:
      • 发送:HTTP 申请发送 cookie,Cookie 字段,一次能够设置多个 cookie,用分号隔开
      • 生成:Http 响应生成 cookie,Set-Cookie 字段,一次设置一个 cookie,但能够有多个 Set-Cookie 字段

XMLHttpRequest

  • const api = new XMLHttpRequest()
  • api.open(method, url, async)
  • api.send(body)
  • api.setRequestHeader()
  • api.getResponseHeader() // 获取参数对应的 simple response header,参数必须在 simple response header 范畴内
  • api.getAllResponseHeader() // 获取所有 simple response header
  • api.onreadystatechange()
  • api.onload()
  • api.onprogress() // 下载进度
  • api.upload.onprogress() // 上传进度信息
  • api.setRequestHeader(name, value)
  • api.responseType // text, document, json, blob, arrayBuffer
  • api.timeout
  • api.abort() // 终止申请
  • api.withCredentidals // 一个布尔值,示意跨域申请时,是否能够携带认证信息,如 cookie

    const api = new XMLHttpRequest()
    
  • 初始化 HTTP 申请参数(url,http 办法等),但并不发送申请,供 send() 办法应用

    api.open(method, url, async, username, password)
    method:HTTP 申请的办法 GET, POST, HEAD
    url:申请的地址
    async:是否异步,默认是 true,即异步的发送申请
    // false:同步,对 send 办法的调用将阻塞,直到响应齐全承受
    // true 或者省略:异步,且通常须要调用 onreadystatechange() 办法

    (2) api.send()

  • 发送一个 http 申请,申请参数写在 send 办法中

    api.send(body)
    get 申请:参数能够写在 open()办法中
    post 申请:参数卸载 send() 办法中

    (3) api.setRequestHeader()

  • 指定一个 HTTP 申请的头部(申请头),只有在 readyState 为 1 时能力调用

    api.setRequestHeader(name, value)
    name: key
    value:value
    留神:setRequestHeader()办法能够屡次调用,最终的值不是笼罩 override 而是追加 append
    留神:setRequestHeader()办法只有在 readyState = 1 时能力调用,即 open()之后 send()之前

    (4) api.getResponseHeader()

  • 返回指定的 HTTP 响应头部的值(响应头)

    (5) api.abort() //abort:停止的意思

  • 勾销以后响应,敞开连贯并且完结任何未决的网络流动
  • api.abort()将 readyState 重置为 0
  • 利用:如果申请用了太长的工夫,而且响应不在必要时,能够调用这个办法

    (6) api.onreadystatechange()

  • api.onreadystatechange()但 readyState = 3 时能够调用屡次
  • 留神:onreadystatechange 都是小写,而 readyState 是驼峰写法

    readyState 状态:

  • UNSENT —————— xhr 对象胜利结构,open()办法未被调用
  • OPEND ——————- open()办法被调用,send()办法还未被调用,setRequestHeader()能够被调用
  • HEADERS_RECEIVED ——– send()办法被调用,响应头和响应状态曾经返回
  • LOADING —————– 响应体(response entity body)正在下载中,此状态下 api.response 可能曾经有了响应数据
  • DONE ——————– 整个数据传输过程完结,不论本次申请是胜利还是失败

    (7) api.onload()

  • api.onload()申请胜利时触发,此时 readyState = 4
  • 申请胜利的回调有两个:
    1. readyState=== 4 时的 api.onreadystatechange()
    1. api.onload()办法
      api.onload = function () {
      // 如果申请胜利
      if(api.status == 200){
      //do successCallback
      }
      }

    留神:status===200 是有坑的,因为协商缓存返回的状态码是 304,申请也是胜利的申请,所以上面的判断跟欠缺
    api.onload = function() {
    if((api.status>=200 && api.status < 300) || api.status === 304) {

      // do successCallback

    }
    }

    (8) api.timeout

  • api.timeout 用来设置过期工夫

    问题 1:申请的开始工夫怎么确定?是 api.onloadstart 事件触发的时候,也就是 api.send()调用的时候
    解析:因为 api.open()只是创立了链接,当并没有真正传输数据,只有调用 api.send()时才真正开始传输
    问题 2:什么时候是申请完结?
    解析:api.loadend 事件触发时完结

    (9) api.onprogress() 下载进度信息
    (10) api.upload.onprogress = function(e) {上传进度信息
    if (e.lengthComputable) {

    const present = e.loaded / e.total * 100;

    }
    }


    1.
    问题 1:如何获取 response
    提供三个属性来获取 response:(api.response) 和 (api.responseText) 和 (responseXML)
    api.responseText — api.responseType=’text’、”、不设置时,xhr 对象上才有此属性,此时能力调用
    api.response — responseType 为 ”” 或 ”text” 时,值为 ””;responseType 为其余值时,值为 null

    2.
    问题 2:api.responseType 有哪些类型
    api.responseType 类型有:text, document, json, blob, arrayBuffer

api.getReponseHeader() 和 api.getAllResponseHeader()

  • api.getResponseHeader()获取参数指定的 simple response header
  • api.getAllResponseHeader() 获取所有 simple resopnse header
  • <font color=red> 留神:这两个办法都不能获取 Set-Cookie,无论是同域还是跨域 </font>
  • <font color=red> 留神:对于跨域申请,客户端只能获取 simple response header 和 Access-Control-Expose-Headers</font>

    • simple response header:

      • Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma
    • Access-Control-Expose-Headers:

      • 只在跨域申请时的响应头中存在,示意服务端容许裸露给客服端的 headers
      • 同域申请的响应中不蕴含该字段
      • expose:是裸露的意思
  • 总结:getAllResponseHeader()只能拿到限度以外的 response header, getResponseHeader()的参数也必须是限度以外的参数,否则会 Refused to get unsafe header 的谬误

api.withCredentials

  • <font color=red>api.withCredentials 一个布尔值,示意跨域申请时,是否能够携带认证信息,默认是 false 即不容许携带 </font>

    • 比方 cookie
  • 留神:在同域申请时,cookie 会在申请头中主动携带,然而在跨域申请时,并没有主动携带,起因是:在 CORS 规范中做了规定,默认状况下,浏览器在发送跨域申请时,不能发送任何认证信息(credentials)如 "cookies" 和 "HTTP authentication schemes"。除非 xhr.withCredentials 为 true
  • 跨域申请:所以跨域申请时

    • 客户端:api.withCredentials = true 设置为 true
    • server 端(响应头):Access-Control-Allow-Credentials:true

案例


get 申请

go() {console.log('1111111111');
      const api = new XMLHttpRequest();
      api.open('GET',  ----- 初始 http 申请参数,申请形式,url, 是否异步
      'https://bing.ioliu.cn/v1/rand?type=json', true);
      api.responseType = 'text';   ------ 文本格式的响应
      api.timeout = 5000; ---- 申请过期工夫
      api.setRequestHeader('Content-type', 'application/json'); ----- 必须在 open()后,send()前设置
      api.onreadystatechange = function() { ------ readyState 扭转时触发
        if (api.readyState === 4 && this.status === 200) { ---- this 指的是 api 实例
          console.log(JSON.parse(this.responseText)) ------ this.response 也能拿到同样的数据
        }
      }
      // 除了在 api.onreadystatechange 指指定的会调中判断 readyState===4,也能够间接在 onload 中触发
      // 两种办法都能够
      // 只判断 200 状态码不欠缺,应该判断 2xx 或者 304 则申请胜利
      api.onload = function() {if ( api.status >= 200 && api.status < 300 || api.status === 304) {console.log(JSON.parse(api.responseText), 'onload 在申请胜利时触发');
        }
      }
      api.send();  ---- 发送数据}

面试精简 https://juejin.im/post/684490…
https://juejin.im/post/684490…
https://juejin.im/post/684490…
美团 https://juejin.im/post/684490…
知乎 https://zhuanlan.zhihu.com/p/…
XMLHttpRequest https://segmentfault.com/a/11…
我的简书 https://www.jianshu.com/p/729…

正文完
 0