计网基础-前端安全

loading 2023年02月05日 186次浏览

1. XSS

跨网站指令码(Cross-site scripting)是一种网站应用程式的安全漏洞攻击,是代码注入的一种。它允许恶意使用者将程式码注入到网页上,其他使用者在观看网页时就会受到影响。这类攻击通常包含了 HTML 以及使用者端脚本语言。

所以,网页上哪些部分会引起XSS攻击?简单来说,任何可以输入的地方都有可能引起,包括URL。

XSS分为以下三类:

  • 存储型XSS:恶意代码存储在后端数据库,插入到HTML中。 这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。
  • 反射型XSS:恶意代码存储在URL中,插入到HTML中。 常见于通过 URL 传递参数的功能,如网站搜索、跳转等。
  • DOM型XSS:存储在后端数据库、前端存储、URL中,插入到前端JS中。 DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞。

1.1 攻击

XSS 通过修改 HTML 节点或者执行 JS 代码来攻击网站。
例如通过 URL 获取某些参数

<!-- http://www.domain.com?name=<script>alert(1)</script> -->
<div>{{name}}</div>

上述 URL 输入可能会将 HTML 改为

 <div><script>alert(1)</script></div>

这样页面中就凭空多了一段可执行脚本。这种攻击类型是反射型攻击,也可以说是 DOM-based 攻击。

也有另一种场景,比如写了一篇包含攻击代码

<script>alert(1)</script>

的文章,那么可能浏览文章的用户都会被攻击到。这种攻击类型是存储型攻击,也可以说是 DOM-based 攻击,并且这种攻击打击面更广。

1.2 防御

1.2.1 转义内容

最普遍的做法是转义输入输出的内容,对于引号,尖括号,斜杠进行转义

function escape(str) {
  str = str.replace(/&/g, '&amp;')
  str = str.replace(/</g, '&lt;')
  str = str.replace(/>/g, '&gt;')
  str = str.replace(/"/g, '&quto;')
  str = str.replace(/'/g, '&#39;')
  str = str.replace(/`/g, '&#96;')
  str = str.replace(/\//g, '&#x2F;')
  return str
}

通过转义可以将攻击代码 变成

escape('<script>alert(1)</script>')
// &lt;script&gt;alert(1)&lt;&#x2F;script&gt;

对于显示富文本来说,不能通过上面的办法来转义所有字符,因为这样会把需要的格式也过滤掉。这种情况通常采用白名单过滤的办法,当然也可以通过黑名单过滤,但是考虑到需要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式。

var xss = require('xss')
var html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>')
console.log(html)
// <h1>XSS Demo</h1>&lt;script&gt;alert("xss");&lt;/script&gt;

1.2.2 CSP

内容安全策略 (CSP) 是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本 (XSS) 和数据注入攻击等。无论是数据盗取、网站内容污染还是散发恶意软件,这些攻击都是主要的手段。

我们可以通过 CSP 来尽量减少 XSS 攻击。CSP 本质上也是建立白名单,规定了浏览器只能够执行特定来源的代码。

通常可以通过 HTTP Header 中的 Content-Security-Policy 来开启 CSP

Content-Security-Policy: default-src 'self'; // 只允许加载本站资源
Content-Security-Policy: img-src https://*  // 只允许加载 HTTPS 协议图片
Content-Security-Policy: child-src 'none'    // 允许加载任何来源框架

2. CSRF

跨站请求伪造,是一种挟持用户在当前已登陆的Web应用程序上执行非本意的操作的攻击方法。如:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。

2.1 攻击

从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:

  1. 登录受信任网站A,并在本地生成Cookie。
  2. 在不登出A的情况下,访问危险网站B。

2.2 防御

  • 验证码: 强制用户必须与应用进行交互,才能完成最终请求。此种方式能很好的遏制 csrf,但是用户体验比较差。
  • Referer check: 根据HTTP协议,在HTTP头中有一个字段叫Referer,记录了该HTTP请求的来源地址。此种方法成本最低,但是并不能保证 100% 有效,因为服务器并不是什么时候都能取到 Referer,而且低版本的浏览器存在伪造 Referer 的风险。
  • token: token 验证的 CSRF 防御机制是公认最合适的方案,前提是页面没有XSS漏洞泄露Token

2.2.1 token

这里顺便展开说说token,CSRF Token的防护策略分为三个步骤:

1. 将CSRF Token输出到页面中
首先,用户打开页面的时候,服务器需要给这个用户生成一个Token,该Token通过加密算法对数据进行加密,一般Token都包括随机字符串和时间戳的组合,显然在提交时Token不能再放在Cookie中了,否则又会被攻击者冒用。因此,为了安全起见Token最好还是存在服务器的Session中,之后在每次页面加载时,使用JS遍历整个DOM树,对于DOM中所有的a和form标签后加入Token。这样可以解决大部分的请求,但是对于在页面加载之后动态生成的HTML代码,这种方法就没有作用,还需要程序员在编码时手动添加Token。

2. 页面提交的请求携带这个Token
对于GET请求,Token将附在请求地址之后,这样URL 就变成 http://url?csrftoken=tokenvalue。 而对于 POST 请求来说,要在 form 的最后加上:

 <input type=”hidden” name=”csrftoken” value=”tokenvalue”/>

3. 服务器验证Token是否正确
当用户从客户端得到了Token,再次提交给服务器的时候,服务器需要判断Token的有效性,验证过程是先解密Token,对比加密字符串以及时间戳,如果加密字符串一致且时间未过期,那么这个Token就是有效的。