随着互联网的发展,各种 Web 应用变得越来越复杂,满足了用户的各种需求的同时,各种网络安全问题也接踵而至。作为前端工程师的我们也逃不开这个问题,今天一起看一看 Web 前端有哪些安全问题以及我们如何去检测和防范这些问题。非前端的攻击本文不会讨论(如 SQL 注入,DDOS 攻击等),毕竟后端也非本人擅长的领域。
QQ 邮箱、新浪微博、YouTube、WordPress 和 百度 等知名网站都曾遭遇攻击,如果你从未有过安全方面的问题,不是因为你所开发的网站很安全,更大的可能是你的网站的流量非常低或者没有攻击的价值。
本文主要讨论以下几种攻击方式: XSS 攻击、CSRF 攻击、点击劫持以及 URL 跳转漏洞。
<font style=”color: #ff302c”>希望大家在阅读完本文之后,能够很好的回答以下几个面试题。</font>
1. 前端有哪些攻击方式?
2. 什么是 XSS 攻击?XSS 攻击有几种类型?如果防范 XSS 攻击?
3. 什么是 CSRF 攻击?如何防范 CSRF 攻击
4. 如何检测网站是否安全?
在开始之前,建议大家先 clone 代码,我为大家准备好了示例代码,并且写了详细的注释,大家可以对照代码来理解每一种攻击以及如何去防范攻击,毕竟看再多的文字,都不如实操。(Readme 中详细得写了操作步骤):https://github.com/YvetteLau/…
1. XSS 攻击
XSS(Cross-Site Scripting,跨站脚本攻击)是一种代码注入攻击。攻击者在目标网站上注入恶意代码,当被攻击者登陆网站时就会执行这些恶意代码,这些脚本可以读取 cookie,session tokens,或者其它敏感的网站信息,对用户进行钓鱼欺诈,甚至发起蠕虫攻击等。
XSS 的本质是:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。由于直接在用户的终端执行,恶意代码能够直接获取用户的信息,利用这些信息冒充用户向网站发起攻击者定义的请求。
XSS 分类
根据攻击的来源,XSS 攻击可以分为存储型 (持久性)、反射型(非持久型) 和 DOM 型三种。下面我们来详细了解一下这三种 XSS 攻击:
1.1 反射型 XSS
当用户点击一个恶意链接,或者提交一个表单,或者进入一个恶意网站时,注入脚本进入被攻击者的网站。Web 服务器将注入脚本,比如一个错误信息,搜索结果等,未进行过滤直接返回到用户的浏览器上。
反射型 XSS 的攻击步骤:
- 攻击者构造出特殊的
URL
,其中包含恶意代码。 - 用户打开带有恶意代码的
URL
时,网站服务端将恶意代码从URL
中取出,拼接在 HTML 中返回给浏览器。 - 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
反射型 XSS 漏洞常见于通过 URL
传递参数的功能,如网站搜索、跳转等。由于需要用户主动打开恶意的 URL
才能生效,攻击者往往会结合多种手段诱导用户点击。
POST 的内容也可以触发反射型 XSS,只不过其触发条件比较苛刻(需要构造表单提交页面,并引导用户点击),所以非常少见。
查看反射型攻击示例
请戳:https://github.com/YvetteLau/…
根据 README.md
的提示进行操作(真实情况下是需要诱导用户点击的,上述代码仅是用作演示)。
注意Chrome
和 Safari
能够检测到 url
上的 xss 攻击,将网页拦截掉,但是其它浏览器不行,如Firefox
如果不希望被前端拿到 cookie,后端可以设置 httpOnly
(不过这不是 XSS 攻击
的解决方案,只能降低受损范围)
如何防范反射型 XSS 攻击
对字符串进行编码。
对 url 的查询参数进行转义后再输出到页面。
app.get('/welcome', function(req, res) {
// 对查询参数进行编码,避免反射型 XSS 攻击
res.send(`${encodeURIComponent(req.query.type)}`);
});
1.2 DOM 型 XSS
DOM 型 XSS 攻击,实际上就是前端 JavaScript
代码不够严谨,把不可信的内容插入到了页面。在使用 .innerHTML
、.outerHTML
、.appendChild
、document.write()
等 API 时要特别小心,不要把不可信的数据作为 HTML 插到页面上,尽量使用 .innerText
、.textContent
、.setAttribute()
等。
DOM 型 XSS 的攻击步骤:
- 攻击者构造出特殊数据,其中包含恶意代码。
- 用户浏览器执行了恶意代码。
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
如何防范 DOM 型 XSS 攻击
防范 DOM 型 XSS 攻击的核心就是对输入内容进行转义(DOM 中的内联事件监听器和链接跳转都能把字符串作为代码运行,需要对其内容进行检查)。
1. 对于 url
链接 (例如图片的src
属性),那么直接使用 encodeURIComponent
来转义。
2. 非url
,我们可以这样进行编码:
function encodeHtml(str) {return str.replace(/"/g,'"')
.replace(/'/g,''')
.replace(/</g, '<')
.replace(/>/g, '>');
}
DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞。
查看 DOM 型 XSS 攻击示例(根据 readme 提示查看)
请戳:https://github.com/YvetteLau/…
1.3 存储型 XSS
恶意脚本永久存储在目标服务器上。当浏览器请求数据时,脚本从服务器传回并执行,影响范围比反射型和 DOM 型 XSS 更大。存储型 XSS 攻击的原因仍然是没有做好数据过滤:前端提交数据至服务端时,没有做好过滤;服务端在接受到数据时,在存储之前,没有做过滤;前端从服务端请求到数据,没有过滤输出。
存储型 XSS 的攻击步骤:
- 攻击者将恶意代码提交到目标网站的数据库中。
- 用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。
- 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。
如何防范存储型 XSS 攻击:
- 前端数据传递给服务器之前,先转义 / 过滤(防范不了抓包修改数据的情况)
- 服务器接收到数据,在存储到数据库之前,进行转义 / 过滤
- 前端接收到服务器传递过来的数据,在展示到页面前,先进行转义 / 过滤
查看存储型 XSS 攻击示例(根据 Readme 提示查看)
请戳:https://github.com/YvetteLau/…
除了谨慎的转义,我们还需要其他一些手段来防范 XSS 攻击:
1.Content Security Policy
在服务端使用 HTTP 的 Content-Security-Policy
头部来指定策略,或者在前端设置 meta
标签。
例如下面的配置只允许加载同域下的资源:
Content-Security-Policy: default-src 'self'
<meta http-equiv="Content-Security-Policy" content="form-action'self';">
前端和服务端设置 CSP 的效果相同,但是 meta
无法使用report
更多的设置可以查看 [Content-Security-Policy
](https://developer.mozilla.org…
严格的 CSP 在 XSS 的防范中可以起到以下的作用:
- 禁止加载外域代码,防止复杂的攻击逻辑。
- 禁止外域提交,网站被攻击后,用户的数据不会泄露到外域。
- 禁止内联脚本执行(规则较严格,目前发现 GitHub 使用)。
- 禁止未授权的脚本执行(新特性,Google Map 移动版在使用)。
- 合理使用上报可以及时发现 XSS,利于尽快修复问题。
2. 输入内容长度控制
对于不受信任的输入,都应该限定一个合理的长度。虽然无法完全防止 XSS 发生,但可以增加 XSS 攻击的难度。
3. 输入内容限制
对于部分输入,可以限定不能包含特殊字符或者仅能输入数字等。
4. 其他安全措施
- HTTP-only Cookie: 禁止 JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注入后也无法窃取此 Cookie。
- 验证码:防止脚本冒充用户提交危险操作。
1.5 XSS 检测
读到这儿,相信大家已经知道了什么是 XSS 攻击,XSS 攻击的类型,以及如何去防范 XSS 攻击。但是有一个非常重要的问题是:我们如何去检测 XSS 攻击,怎么知道自己的页面是否存在 XSS 漏洞?
很多大公司,都有专门的安全部门负责这个工作,但是如果没有安全部门,作为开发者本身,该如何去检测呢?
1. 使用通用 XSS 攻击字串手动检测 XSS 漏洞
如: jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
能够检测到存在于 HTML 属性、HTML 文字内容、HTML 注释、跳转链接、内联 JavaScript 字符串、内联 CSS 样式表等多种上下文中的 XSS 漏洞,也能检测 eval()、setTimeout()、setInterval()、Function()、innerHTML、document.write() 等 DOM 型 XSS 漏洞,并且能绕过一些 XSS 过滤器。
<img src=1 onerror=alert(1)>
2. 使用第三方工具进行扫描(详见最后一个章节)
__
2. CSRF
CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。
典型的 CSRF 攻击流程:
- 受害者登录 A 站点,并保留了登录凭证(Cookie)。
- 攻击者诱导受害者访问了站点 B。
- 站点 B 向站点 A 发送了一个请求,浏览器会默认携带站点 A 的 Cookie 信息。
- 站点 A 接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是无辜的受害者发送的请求。
- 站点 A 以受害者的名义执行了站点 B 的请求。
- 攻击完成,攻击者在受害者不知情的情况下,冒充受害者完成了攻击。
一图胜千言:
CSRF 的特点
1. 攻击通常在第三方网站发起,如图上的站点 B,站点 A 无法防止攻击发生。
2. 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;并不会去获取 cookie 信息(cookie 有同源策略)
3. 跨站请求可以用各种方式:图片 URL、超链接、CORS、Form 提交等等(来源不明的链接,不要点击)
运行代码,更直观了解一下
用户 loki 银行存款 10W。
用户 yvette 银行存款 1000。
我们来看看 yvette 如何通过 CSRF
攻击,将 loki 的钱偷偷转到自己的账户中,并根据提示,查看如何去防御 CSRF 攻击。
请戳:https://github.com/YvetteLau/… [根据 readme 中的 CSRF 部分进行操作]
CSRF 攻击防御
1. 添加验证码(体验不好)
验证码能够防御 CSRF 攻击,但是我们不可能每一次交互都需要验证码,否则用户的体验会非常差,但是我们可以在转账,交易等操作时,增加验证码,确保我们的账户安全。
2. 判断请求的来源:检测 Referer(并不安全,Referer 可以被更改)
`Referer` 可以作为一种辅助手段,来判断请求的来源是否是安全的,但是鉴于 `Referer` 本身是可以被修改的,因为不能仅依赖于 `Referer`
3. 使用 Token(主流)
CSRF 攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个 CSRF 攻击者无法获取到的 Token。服务器通过校验请求是否携带正确的 Token,来把正常的请求和攻击的请求区分开。跟验证码类似,只是用户无感知。- 服务端给用户生成一个 token,加密后传递给用户
- 用户在提交请求时,需要携带这个 token
- 服务端验证 token 是否正确
4. Samesite Cookie 属性
为了从源头上解决这个问题,Google 起草了一份草案来改进 HTTP 协议,为 Set-Cookie 响应头新增 Samesite 属性,它用来标明这个 Cookie 是个“同站 Cookie”,同站 Cookie 只能作为第一方 Cookie,不能作为第三方 Cookie,Samesite 有两个属性值,分别是 Strict 和 Lax。
部署简单,并能有效防御 CSRF 攻击,但是存在兼容性问题。
Samesite=Strict
Samesite=Strict
被称为是严格模式, 表明这个 Cookie 在任何情况都不可能作为第三方的 Cookie,有能力阻止所有 CSRF 攻击。此时,我们在 B 站点下发起对 A 站点的任何请求,A 站点的 Cookie 都不会包含在 cookie 请求头中。
**Samesite=Lax**
`Samesite=Lax` 被称为是宽松模式,与 Strict 相比,放宽了限制,允许发送安全 HTTP 方法带上 Cookie,如 `Get` / `OPTIONS`、`HEAD` 请求.
但是不安全 HTTP 方法,如:`POST`, `PUT`, `DELETE` 请求时,不能作为第三方链接的 Cookie
为了更好的防御 CSRF 攻击,我们可以组合使用以上防御手段。
3. 点击劫持
点击劫持是指在一个 Web 页面中隐藏了一个透明的 iframe,用外层假页面诱导用户点击,实际上是在隐藏的 frame 上触发了点击事件进行一些用户不知情的操作。
典型点击劫持攻击流程
- 攻击者构建了一个非常有吸引力的网页【不知道哪些内容对你们来说有吸引力,我就不写页面了,偷个懒】
- 将被攻击的页面放置在当前页面的
iframe
中 - 使用样式将 iframe 叠加到非常有吸引力内容的上方
- 将 iframe 设置为 100% 透明
- 你被诱导点击了网页内容,你以为你点击的是*,而实际上,你成功被攻击了。
点击劫持防御
1. frame busting
Frame busting
if (top.location != window.location){top.location = window.location}
需要注意的是: HTML5 中 iframe 的 sandbox
属性、IE 中 iframe 的security
属性等,都可以限制 iframe 页面中的 JavaScript 脚本执行,从而可以使得 frame busting 失效。
2. X-Frame-Options
X-FRAME-OPTIONS 是微软提出的一个 http 头,专门用来防御利用 iframe 嵌套的点击劫持攻击。并且在 IE8、Firefox3.6、Chrome4 以上的版本均能很好的支持。
可以设置为以下值:
- DENY: 拒绝任何域加载
- SAMEORIGIN: 允许同源域下加载
- ALLOW-FROM: 可以定义允许 frame 加载的页面地址
4. URL 跳转漏洞
URL 跳转漏洞是指后台服务器在告知浏览器跳转时,未对客户端传入的重定向地址进行合法性校验,导致用户浏览器跳转到钓鱼页面的一种漏洞。
URL 跳转一般有以下几种实现方式
- Header 头跳转
- Javascript 跳转
- META 标签跳转
URL 跳转漏洞防御
之所以会出现跳转 URL 漏洞,就是因为服务端没有对客户端传递的跳转地址进行合法性校验,所以,预防这种攻击的方式,就是对客户端传递过来的跳转 URL 进行校验。
1.referer 的限制
如果确定传递 URL 参数进入的来源,我们可以通过该方式实现安全限制,保证该 URL 的有效性,避免恶意用户自己生成跳转链接
2. 加入有效性验证 Token
保证所有生成的链接都是来自于可信域,通过在生成的链接里加入用户不可控的 token 对生成的链接进行校验,可以避免用户生成自己的恶意链接从而被利用。
安全扫描工具
上面我们介绍了几种常见的前端安全漏洞,也了解一些防范措施,那么我们如何发现自己网站的安全问题呢?没有安全部门的公司可以考虑下面几款开源扫码工具:
1. Arachni
Arachni 是基于 Ruby 的开源,功能全面,高性能的漏洞扫描框架,Arachni 提供简单快捷的扫描方式,只需要输入目标网站的网址即可开始扫描。它可以通过分析在扫描过程中获得的信息,来评估漏洞识别的准确性和避免误判。
Arachni 默认集成大量的检测工具,可以实施 代码注入、CSRF、文件包含检测、SQL 注入、命令行注入、路径遍历等各种攻击。
同时,它还提供了各种插件,可以实现表单爆破、HTTP 爆破、防火墙探测等功能。
针对大型网站,该工具支持会话保持、浏览器集群、快照等功能,帮助用户更好实施渗透测试。
2. Mozilla HTTP Observatory
Mozilla HTTP Observatory,是 Mozilla 最近发布的一款名为 Observatory 的网站安全分析工具,意在鼓励开发者和系统管理员增强自己网站的安全配置。用法非常简单:输入网站 URL,即可访问并分析网站 HTTP 标头,随后可针对网站安全性提供数字形式的分数和字母代表的安全级别。
检查的主要范围包括:
- Cookie
- 跨源资源共享(CORS)
- 内容安全策略(CSP)
- HTTP 公钥固定(Public Key Pinning)
- HTTP 严格安全传输(HSTS)状态
- 是否存在 HTTP 到 HTTPs 的自动重定向
- 子资源完整性(Subresource Integrity)
- X-Frame-Options
- X-XSS-Protection
3. w3af
W3af 是一个基于 Python 的 Web 应用安全扫描器。可帮助开发人员,有助于开发人员和测试人员识别 Web 应用程序中的漏洞。
扫描器能够识别 200 多个漏洞,包括跨站点脚本、SQL 注入和操作系统命令。
参考文章:
[1] https://github.com/0xsobky/Ha…
[2] https://tech.meituan.com/2018…
[3] https://zhuanlan.zhihu.com/p/…
[4] https://mp.weixin.qq.com/s/up…
[5] https://juejin.im/post/5b4e0c…
[6] https://juejin.im/post/5c8a33…
[7] https://github.com/OWASP/Chea…
关注小姐姐的公众号,和小姐姐一起学前端。
后续写作计划(写作顺序不定)
1.《寒冬求职季之你必须要懂的原生 JS》(下)
2.《寒冬求职季之你必须要知道的 CSS》
3.《寒冬求职季之你必须要懂的一些浏览器知识》
4.《寒冬求职季之你必须要知道的性能优化》
5.《寒冬求职季之你必须要懂的 webpack 原理》
针对 React 技术栈:
1.《寒冬求职季之你必须要懂的 React》系列
2.《寒冬求职季之你必须要懂的 ReactNative》系列
编写本文,虽然花费了很多时间,但是在这个过程中,我也学习到了很多知识,谢谢各位小伙伴愿意花费宝贵的时间阅读本文,如果本文给了您一点帮助或者是启发,请不要吝啬你的赞和 Star,您的肯定是我前进的最大动力。https://github.com/YvetteLau/…