阅读 134

是个前端都应该了解的web安全知识(附一些较新的防范方法)

前言

对于很多刚开始工作的前端而言,web安全似乎是一个说不清道不明的东西。关于web安全,认真学习总结一下,其实就会发现它不难。本文通过面试提问的形式来一一进行总结,希望对于各位小伙伴理解web安全有所帮助。

1.前端有哪些攻击方式?

目前常见的web攻击方式主要分为:XSS攻击、CSRF攻击、点击劫持。

2.什么是XSS攻击?XSS攻击有哪几种类型?如何防范XSS攻击?

2.1 什么是XSS攻击?

XSS(Cross-Site Scripting,跨站脚本攻击)是一种代码注入攻击。攻击者在目标网站上注入恶意代码,当被攻击者登录网站时就会执行这些恶意代码。这些脚本可以读取cookie、session tokens或者其他敏感的网站信息,对用户进行钓鱼欺诈,甚至发起蠕虫攻击等。

XSS的本质是:恶意代码未经过滤,与网站正常的代码混在一起,而浏览器是无法辨别哪些脚本是恶意的,导致恶意脚本被执行。由于直接在用户的终端执行,恶意代码能够直接获取用户的信息,利用这些信息冒充用户向网站发起攻击者定义的请求。

举个简单的例子:

<a href="#" onclick="doAttack()">
    click me
    <script type="text/javascript">
        function doAttack() {
            while (true) {
                alert('u are under attack');
            }
        }
    </script>
</a>
复制代码

这里在a标签里注入一个脚本,当用户点击后,浏览器会一直弹窗。在真实的网站攻击中,攻击者通过注入的这个脚本,它可以随意干坏事,这样是非常危险的。因为前端你用JavaScript进行的操作,它也一样能,想想是不是觉得很恐怖?

2.2 XSS攻击有哪几种类型?

根据攻击的来源,XSS可以分为存储型(持久型)、反射型(非持久型)、DOM型三种。

  1. 反射型XSS

当用户点击一个恶意链接,或者提交一个表单,或者进入一个恶意网站时,注入脚本进入被攻击者的网站。Web服务器将注入一个脚本,比如一个错误信息、搜索结果等,未进行过滤直接返回到用户的浏览器上。

反射型XSS的攻击步骤:

  • 攻击者构造出特殊的url,其中包含恶意代码。
  • 用户打开带有恶意代码的url时,网站服务端将恶意代码从url取出,拼接在HTML中返回给用户。
  • 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
  • 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

反射型 XSS 漏洞常见于通过 URL 传递参数的功能,如网站搜索、跳转等。由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击。 注意Chrome 和 Safari 能够检测到 url 上的xss攻击,将网页拦截掉,但是其它浏览器不行,如Firefox。 如果不希望被前端拿到cookie,后端可以设置 httpOnly (不过这不是 XSS攻击 的解决方案,只能降低受损范围)。

  1. DOM型XSS

DOM 型 XSS 攻击,实际上就是前端 JavaScript 代码不够严谨,把不可信的内容插入到了页面。在使用 .innerHTML、.outerHTML、.appendChild、document.write()等API时要特别小心,不要把不可信的数据作为 HTML 插到页面上,尽量使用 .innerText、.textContent、.setAttribute() 等。

DOM 型 XSS 的攻击步骤:

  • 攻击者构造出特殊数据,其中包含恶意代码。
  • 用户浏览器执行了恶意代码。
  • 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞。

  1. 存储型XSS

恶意脚本永久存储在目标服务器上。当浏览器请求数据时,脚本从服务器传回并执行,影响范围比反射型和DOM型XSS更大。存储型XSS攻击的原因仍然是没有做好数据过滤:前端提交数据至服务端时,没有做好过滤;服务端在接受到数据时,在存储之前,没有做过滤;前端从服务端请求到数据,没有过滤输出。

存储型 XSS 的攻击步骤:

  • 攻击者将恶意代码提交到目标网站的数据库中。
  • 用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。
  • 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
  • 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。

2.3 如何防范XSS攻击?

2.3.1 防范反射型XSS攻击

app.get('/welcome', function(req, res) {
    //对查询参数进行编码,避免反射型 XSS攻击
    res.send(`${encodeURIComponent(req.query.type)}`); 
});
复制代码

2.3.2 防范DOM型XSS攻击

防范 DOM 型 XSS 攻击的核心就是对输入内容进行转义(DOM 中的内联事件监听器和链接跳转都能把字符串作为代码运行,需要对其内容进行检查)。

  • 对于url链接(例如图片的src属性),那么直接使用 encodeURIComponent 来转义。
  • 非url,我们可以这样进行编码:
function encodeHtml(str) {
    if(!str) return '';
    return str.replace(/"/g, '&quot;')
            .replace(/'/g, '&apos;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/&/g, '&amp');
}
复制代码

2.3.3 防范存储型XSS攻击

  • 前端数据传递给服务器之前,先转义/过滤(防范不了抓包修改数据的情况)
  • 服务器接收到数据,在存储到数据库之前,进行转义/过滤
  • 前端接收到服务器传递过来的数据,在展示到页面前,先进行转义/过滤

2.3.4 CSP方式

CSP的全称是Content Security Policy,即内容安全策略。

CSP 的主要目标是减少和报告 XSS 攻击 ,XSS 攻击利用了浏览器对于从服务器所获取的内容的信任。恶意脚本在受害者的浏览器中得以运行,因为浏览器信任其内容来源,即使有的时候这些脚本并非来自于它本该来的地方。

CSP通过指定有效域——即浏览器认可的可执行脚本的有效来源——使服务器管理者有能力减少或消除XSS攻击所依赖的载体。一个CSP兼容的浏览器将会仅执行从白名单域获取到的脚本文件,忽略所有的其他脚本 (包括内联脚本和HTML的事件处理属性)。

作为一种终极防护形式,始终不允许执行脚本的站点可以选择全面禁止脚本执行。

如何使用CSP?

你可以使用 Content-Security-Policy HTTP头部 来指定你的策略,像这样:

Content-Security-Policy: policy

policy参数是一个包含了各种描述你的CSP策略指令的字符串。

比如一个网站管理者想要所有内容均来自站点的同一个源 (不包括其子域名):

Content-Security-Policy: default-src 'self'

详细的用法可以参考MDN,内容安全策略( CSP )

3. 什么是CSRF攻击?如何防范?

3.1 什么是CSRF攻击?

CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。

典型的CSRF攻击流程:

  1. 受害者登录A站点,并保留了登录凭证(Cookie)。
  2. 攻击者诱导受害者访问了站点B。
  3. 站点B向站点A发送了一个请求,浏览器会默认携带站点A的Cookie信息。
  4. 站点A接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是无辜的受害者发送的请求。
  5. 站点A以受害者的名义执行了站点B的请求。
  6. 攻击完成,攻击者在受害者不知情的情况下,冒充受害者完成了攻击。

3.2 如何防范CSRF攻击?

3.2.1 主流方式

  1. 添加验证码(体验不好)
  2. 判断请求的来源:检测Referer(并不安全,Referer可以被更改)
  3. 使用Token(主流)

CSRF攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个CSRF攻击者无法获取到的Token。服务器通过校验请求是否携带正确的Token,来把正常的请求和攻击的请求区分开。跟验证码类似,只是用户无感知。

  • 服务端给用户生成一个token,加密后传递给用户
  • 用户在提交请求时,需要携带这个token
  • 服务端验证token是否正确

3.2.2 启用cookies的SameSite属性

SameSite的属性值有3个:

  • strict: Cookie只会在第一方上下文中发送,不会与第三方网站发起的请求一起发送。
  • lex: Cookies允许与顶级一起发送,并将与第三方网站发起的GET请求一起发送。这是浏览器中的默认值。
  • none: Cookie将在所有上下文中发送,即允许跨域发送。

注意:以前None是默认值,但最近的浏览器版本将Lax作为默认值,以便对某些类型的跨站点请求伪造(csrf)攻击具有相当强的防御能力。

4. 什么是点击劫持攻击?如何防范?

4.1 什么是点击劫持攻击?

点击劫持是指在一个Web页面中隐藏了一个透明的iframe,用外层假页面诱导用户点击,实际上是在隐藏的frame上触发了点击事件进行一些用户不知情的操作。

典型的点击劫持攻击流程:

  1. 攻击者构建了一个非常有吸引力的网页
  2. 将被攻击的页面放置在当前页面的 iframe 中
  3. 使用样式将 iframe 叠加到非常有吸引力内容的上方
  4. 将iframe设置为100%透明
  5. 你被诱导点击了网页内容,你以为你点击的是***,而实际上,你成功被攻击了。

4.2 如何防范点击劫持?

4.2.1 frame busting

if (top.location !== window.location) {
    top.location = window.location;
}
复制代码

需要注意的是: HTML5中iframe的 sandbox 属性、IE中iframe的security 属性等,都可以限制iframe页面中的JavaScript脚本执行,从而可以使得 frame busting 失效。

4.2.2 X-FRAME-OPTIONS

X-FRAME-OPTIONS是微软提出的一个http头,专门用来防御利用iframe嵌套的点击劫持攻击。并且在IE8、Firefox3.6、Chrome4以上的版本均能很好的支持。可以设置为以下值:

  • DENY: 拒绝任何域加载
  • SAMEORIGIN: 允许同源域下加载
  • ALLOW-FROM: 可以定义允许frame加载的页面地址

5. 总结

以上谈到了3种web攻击方式,分别是XSS攻击、CSRF攻击、点击劫持,并给出了具体的防范方式。当然,只有在实践中不断地使用这些技术,才能对web安全有更深刻的认知。