同源策略、XSS和CSRF攻击


随着互联网的高速发展,信息安全问题已经成为企业最为关注的焦点之一,而前端又是引发企业安全问题的高危据点。在移动互联网时代,特别是前端人员除了传统的 XSS、CSRF 等安全问题之外,又时常遭遇网络劫持、非法调用 Hybrid API 等新型安全问题。当然,浏览器自身也在不断在进化和发展,不断引入 CSP、SameSite、HttpOnly、Cookies 等新技术来增强安全性,但是仍存在很多潜在的威胁,这需要我们不断进行“查漏补缺”

浏览器安全可以分为三大块:Web页面安全、浏览器网络安全、浏览器系统安全

Web页面安全主要就是同源策略限制

什么是同源策略

同源指的是我们访问站点的:协议域名端口号必须一至,才叫同源

浏览器默认同源之间的站点是可以相互访问资源和操作DOM的,而不同源之间想要互相访问资源或者操作DOM,那就需要加一些安全策略的限制,俗称同源策略

同源策略主要限制了三个方面:

  1. DOM层面:不同源站点之间不能相互访问和操作DOM
  2. 数据层面:不能获取不同源站点的Cookie、LocalStorage、indexDB等数据
  3. 网络层面:不能通过XMLHttpRequest向不同源站点发送请求

当然同源策略限制也不是绝对隔离不同源的站点,比如link、img、script标签都没有跨域限制,这让我们开发更灵活了,但是也同样带来了一些安全问题,也就是浏览器网络安全问题,最典型的就是XSS攻击和CSRF攻击

说一下XSS攻击

XSS攻击是一种代码注入攻击,通过恶意注入脚本在浏览器运行,然后盗取用户信息

造成XSS攻击其实本质上还是因为网站没有过滤恶意代码,与正常代码混在一起之后,浏览器没有办法分辨哪些是可信的,然后导致恶意代码也被执行。然后可能导致以下情况:

  • 页面数据或用户信息被窃取,如DOM、Cookie、LocalStorage
  • 修改DOM,比如伪造登录窗口或在页面生成浮窗广告
  • 监听用户行为,比如在登录或银行等站点用 addEventListener 监听键盘事件,窃取账号密码等信息
  • 流量被劫持向其他网站

XSS攻击有三种类型:存储型反射型DOM型

  1. 存储型:是在有发贴评论等带有数据保存功能的网站的input、textarea将恶意代码提交到网站数据库中,如<script src="http://恶意网站"></script> ,然后比如在显示评论的页面就会从数据获取,并直接执行这个script标签里的恶意代码

  2. 反射型:是攻击者将恶意JS脚本作为用户发送给网站请求中的一部分,然后网站又把恶意脚本返回给用户,这时候就会在页面中被执行。比如打开包含带恶意脚本的链接,当打开后会向服务器请求后,服务器会获取URL中的数据然后拼接在HTML上返回,然后执行。它和存储型不同的是不会储存在服务器里

  3. 基于DOM型:就是攻击者通过一些劫持手段,在页面资源传输过程中劫持并修改页面的数据,插入恶意代码

怎么防范XSS攻击,有什么解决办法?

  • 就是对输入框的内容进行过滤或使用转义符进行转码

    字符 转义后的字符
    < &lt;
    > &gt;
    &quot;
    &#x27;
    / &#x2F
    & &amp;
  • 使用CSP,就是白名单,告诉浏览器哪些外部资源可以加载执行,让即使插入进来恶意代码的也不会执行,或者可以向哪些第三方站点提交数据。开启白名单的方式有两种:

    • 使用 meta 标签 <meta http-equiv="Content-Security-Policy">
    • 设置http头部的 Content-Security-Policy
  • 对一些敏感信息进行保护,在Cookie信息中添加httpOnly,告诉浏览器在保存Cookie,且不要对客户端脚本开放访问权限,然后就不能通过document.cookie获取cookie了

    1
    Set-Cookie: widget_session=123456; httpOnly
  • 使用验证码,避免脚本伪装成用户执行一些操作

说一下CSRF攻击

就是跨站请求伪造攻击主要就是利用用户的登录状态发起跨站请求,比如邮箱里的乱七八糟的链接,打开链接的时候邮箱肯定是处于登录状态,然后黑客就可以用这个登录状态,伪造带有正确 Cookie 的 http 请求,直接绕过后台的登录验证,然后冒充用户执行一些操作

发起CSRF攻击有三个必要条件:

  1. 目标网站一定要有CSRF漏洞
  2. 用户登录过目标网站,并且浏览器保存了登录状态
  3. 需要用户主动打开第三方站点

本质是利用cookie在同源请求中携带发送给服务器的特点,来实现冒充用户

CSRF攻击也有三种类型:GET类型POST类型链接型

  • 自动发GET类型:比如imgiframe标签等,当用户打开这个网站时会自动发起带Cookie的资源请求
    1
    <img src="http://恶意网址" >
  • 自动发POST类型:比如整一个隐藏的表单,在用户进入页面的时候自动提交表单
    1
    2
    3
    4
    <form id="hack" action="https://恶意网址" method="post">
    ...
    </form>
    <script>document.getElementById('hack').submit()</script>
  • 诱导链接型:就是诱导用户主动点击链接,比如a标签
    1
    2
    <a href="https://恶意网址">点击领取大礼包</a>
    <a href="https://恶意网址">点击下载美女视频</a>

怎么防范CSRF攻击,有什么解决办法?

  1. 在Cookie信息中添加SameSite属性,这个属性有三个值:

    • strict严格模式,完全禁止使用Cookie
    • lax宽松模式,允许部分情况使用Cookie,跨域的都行,a标签跳转,link标签,GET提交表单
    • none:任何情况下都会发送Cookie,但必须同时设置Secure属性,意思是需要安全上下文,Cookie 只能通过https发送,否则无效

    Chrome 80之前默认值是none,之后是lax

    1
    Set-Cookie: widget_session=123456; SameSite=None; Secure
  2. 验证请求来源:服务器根据http请求头中的OriginReferer属性判断是否为允许访问的站点,从而对请求进行过滤。优先判断Origin,如果两个都不存在的话就直接阻止。

    • Referer:记录了请求是从哪个链接跳过来的并且包含了路径信息,也就是来源地址。不过这家伙不太可靠,所以后来又新增了Origin属性
      1
      Referer: https://juejin.cn/editor/drafts/xxxx
    • origin:记录了域名信息,没有具体的URL路径
      1
      Origin: https://juejin.cn
  3. Token验证:服务器向用户返回一个随机数Token,再次请求时在请求头中以参数的形式添加入这个Token,然后服务器验证这个Token,如果没有或者内容不正确,就拒绝请求。缺点是

    • 每个请求都得添加比较繁琐
    • 单方面验证Cookie可能会被冒用,
    • 如果网站不止一台服务器,通过负载均衡转到了其他服务器的话,其他所有服务器中的Session中都得保留Token,不然就验证不了了
  4. 双重验证Cookie:利用攻击者只能利用Cookie,不能获取Cookie的特点,用户访问页面时,服务器向请求域名添加一个Cookie随机字符串,然后,用户再次请求时从Cookie中取出这个字符串,添加到URL参数中,然后服务器通过对Cookie中的数据和参数中的数据对比验证,不一样就拒绝请求。

    缺点是如果网站存在XSS漏洞,这法子就会失效,而且不能做到子域名的隔离


文章作者: 沐华
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 沐华 !