简单分析XSS与CSRF

Author Avatar
GeniusFunny 3月 05, 2020
  • 在其它设备中阅读本文章

浏览器安全策略

同源策略

浏览器的同源策略限制了来自不同源的 document脚本,对当前文档读取或者设置某些属性。

同源:协议、域名、端口三者都相同,则算同源

同源策略是浏览器为了保证资源的安全性和私密性,只有浏览器存在同源策略

同源策略限制的元素:

  • Cookie、LocalStorage、IndexDB等存储性内容
  • DOM
  • XHR
  • 这些带 src 属性的标签每次加载时,实际上是由浏览器发起了一次GET请求
  • 通过 src属性加载的资源,浏览器限制了JavaScript的权限,使其不能读写返回的内容
跨域常见手段
  • window.domain + iframe大法用于不同子域的iframe通信

    • 该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式
    • 只需要给页面添加 document.domain ='test.com' 表示二级域名都相同就可以实现跨域。(两个页面都通过js强制设置document.domain为基础主域,就实现了同域。)
  • location.hash + iframe:通过修改location.hash值,对应页面检测到hashchange做出响应来实现双向通信

    • 父窗口可以对iframe进行URL读写,iframe也可以读写父窗口的URL
    • IE、chrome下,若跨域 无法直接修改parent.localtion.hash:在iframe页面嵌入一个与父页面同域的iframe
  • HTML5提供的postMessage:

    • 解决的问题:
      • 页面和其打开的新窗口的数据传递
      • 多窗口之间消息传递
      • 页面与嵌套的iframe消息传递
    • 实现方案:
      • A页面:otherWindow.postMessage(message, targetOrigin)
      • B页面:监听message事件
  • window.name + iframe

    • window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。
  • jsonp跨域

    利用<script>标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的JSON数据。JSONP请求一定需要对方的服务器支持才可以。

    • 前端页面声明一个回调函数,通过script标签向API发起请求并带上查询字符串callback=函数名

    • 服务器收到请求后,解析得到函数名(例如show),返回show(要传输的数据字符串)给浏览器

    • 浏览器得到响应,客户端就会调用之前声明的回调函数

    • 实现:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      function jsonp({url, params, callback}) {
      return new Promise((resolve, reject) => {
      let scrpt = document.createElement('script')
      window[callback] = function(data) {
      resolve(data)
      document.body.removeChild(script)
      }
      params = {...params, callback}
      let arrs = []
      for (const key in params) {
      arrs.push(`${key}=${params[key]}`)
      }
      script.src = `${url}?${arrs.join('&')}`
      document.body.appendChild(scrip)
      })
      }
  • Websocket

    • WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据
    • 同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。
  • Nginx反向代理

    • 通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机
    • 反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录
  • Node中间层:同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略。

    • 接受客户端请求 。
    • 将请求转发给服务器。
    • 拿到服务器响应数据。
    • 将响应转发给客户端。
  • CORS

    • CORS需要浏览器和后端同时支持,IE8和IE9需要通过XDomainRequest来实现

    • 服务端设置Access-Control-Allow-Origin就可以开启CORS,该属性表示哪些域名可以访问资源。

    • 简单请求,同时满足下列2个条件就属于简单请求

      • 使用下列方法之一:GET、HEAD、POST
      • Content-Type的值局限于下列三者之一:text/plain、multipart/form-data、application/x-www-form-urlencoded
    • 复杂请求:不是简单请求的就是复杂请求

      • 复杂请求的CORS请求,会在正式通信前,增加一次HTTP查询请求,称为“预检”请求,方法为Option,通过该请求来知道服务端是否允许跨域请求。

浏览器沙箱 sandbox

Chrome、IE都是多进程架构,每个tab是一个进程,进程之间资源互相隔离。

恶意网站拦截

通过设置黑名单,防止用户访问或请求黑名单上的网站或资源。

CSP:Content Security Policy

  • 禁止加载外域代码,防止复杂的攻击逻辑
  • 禁止外域提交,网站被攻击后,用户的数据不会泄露到外域
  • 禁止内联脚本执行
  • 禁止未授权的脚本执行
  • 合理使用上报可以及时发现 XSS,利于尽快修复问题

XSS

XSS

XSS(Cross Site Script,跨站脚本攻击),通过 HTML注入篡改网页(插入恶意脚本)达到攻击的方式。

本质:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。

实现

XSS分类:

  • 反射型XSS:恶意代码存储在url中,需要与用户交互才能触发
    • 攻击者构造出特殊的url,其中包含恶意代码
    • 用户打开带有恶意代码的url时,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器
    • 浏览器接收到响应后解析执行,恶意脚本也得到执行
  • 存储型XSS:将用户包含恶意脚本的输入存储到服务端
    • 攻击者将恶意代码存储到网站服务器【数据库】
    • 用户访问网站时,浏览器从服务器拉取恶意代码拼接在HTML上
    • 浏览器接收到响应后解析执行,恶意脚本也得到执行
  • DOM Based XSS:通过 修改页面的DOM节点 形成的XSS
    • 例:【待补充

危害

  • XSS Payload
    • Cookie劫持:通过植入的恶意脚本读取浏览器的cookie对象 document.cookie
      • 解决方法一:在服务端配置Cookie【HttpOnly】,脚本无法直接读取Cookie
      • 解决方法二:将Cookie与IP绑定,这样即使恶意脚本窃取了Cookie,其他用户也无法用此cookie发生事务(除非伪造IP
    • 构造GET/POST请求
      • 构造GET请求比较容易,借助天然跨域的<img>即可,将请求地址设置为图片的src。
      • 对于POST请求,要麻烦一些(需要插入下面的恶意代码,然后发起请求)
        • 构造form表单,提交
        • 通过XHR发起POST请求
  • XSS 钓鱼: 通过XSS脚本伪造页面欺骗用户
  • 识别用户系统层面的信息,例如浏览器版本、安装的软件、IP地址等

预防

XSS本质就是JavaScript脚本注入,所以可通过检查输入输出来预防

  • 输入检查
    • 结合XSS特性对字符串进行转译【例如:转译<script><base>等】 、 XSS filter
    • 但可能会破坏上下文语境,只针对部分有用,不推荐
  • 输出过滤:存储型XSS和反射型XSS都是将恶意代码拼接到HTML上
    • 纯前端渲染:前后端分离,数据与表现分离,所以能很好的避免XSS(SEO解决?DOM型XSS也无法避免)
    • 对HTML进行转义
  • 白名单: 处理富文本
  • 预防DOM 型 XSS 攻击
    • 谨慎使用可将数据插入到文档中,谨防插入恶意代码

CSRF

img

CSRF(跨站点请求伪造)利用用户的登录态发起恶意请求

CSRF

原理

  • 利用用户在被攻击网站的登录态,使得在进行跨站请求是通过了服务端的验证
  • 浏览器允许发送第三方cookie【广告精准投放的基础】

实现

  • Session-Cookie
    • 未设置cookie过期时间,cookie存储在内存中
    • 由于一个tab拥有一块内存,所以 同一tab下即使不同域 实际上共享Session-Cookie
    • 【Third Party COokie,设置了过期时间,存储在本地,在 同一域下所有tab共享】
  • P3P(The Platform for Privacy Preferences)
    • 如果HTTP设置了P3P头,那么允许浏览器发送第三方cookie

预防

  • CSRF发生在第三方域名
    • 同源检测
      • Origin:若Origin存在可通过Origin来确认域。
        • 对于IE:
          • IE不会在跨站CORS请求头上加上Origin标头
          • 在302重定向后,Orgin不包含在重定向的请求中
      • Referrer
        • 使用方法:HTTP头、<meta>标签、referrerpolicy属性
        • Referrer-Policy值:
          • no-referrer【不发送】
          • no-referrer-when-downgrade【HTTPS—> HTTP,不发送】
          • same-origin【同源时发送】
          • origin【只发送源信息】
          • strict-origin【HTTPS—>HTTP不发送,其余同origin】
          • origin-when-cross-origin【同源时发送完整字段,跨域时同origin】
          • strict-origin-when-cross-origin【同源发送,跨域&降级不发送,跨域只发送origin】
          • unsafe-url【字段包含源信息、路径和查询字符串,不包含锚点、用户名和密码】
    • Samesite Cookie【用于限制第三方Cookie,同时子域也被限制。。。。】
      • Strict:禁止第三方Cookie
      • Lax:GET请求ok
      • None
  • CSRF不能获取到Cookie等信息,只是可以使用
    • Anti CSRF Token
      1. 服务端配置token,将token输出到页面中
      2. 页面提交请求的时候携带token
      3. 服务器验证token是否有效
    • 双重Cookie验证
      • 由于CSRF通常无法获取到cookie,我们可以将cookie中的某key-value添加到请求url参数上,后端收到请求后进行验证
      • 缺点:任何跨域都无法获取到cookie【包括子域名】、不能对用于双重验证的cookie设置http-only【存在XSS修改cookie风险】
  • 验证码:强制用户在发送请求时验证
  • 保持页面的幂等性,GET操作不要做用户操作

总结

在日常业务开发中,推荐按照《白帽子讲Web安全》中提出的安全方案设计法则来去应对潜在的安全问题。

  • Secure By Default: 黑白名单、最小权限原则
  • 纵深防御原则
  • 数据与代码分离原则
  • 不可预测性原则