前端安全
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,只不过其触发条件比较苛刻(需要构造表单提交页面,并引导用户点击),所以非常少见。
注意Chrome
和 Safari
能够检测到 url
上的xss攻击,将网页拦截掉,但是其它浏览器不行,如Firefox
如果不希望被前端拿到cookie,后端可以设置 httpOnly
(不过这不是 XSS攻击
的解决方案,只能降低受损范围)
如何防范反射型XSS攻击
对字符串进行编码。
对url的查询参数进行转义后再输出到页面。
1 | app.get('/welcome', function(req, res) { |
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
,我们可以这样进行编码:
1 | function encodeHtml(str) { |
DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞。
1.3 存储型XSS
恶意脚本永久存储在目标服务器上。当浏览器请求数据时,脚本从服务器传回并执行,影响范围比反射型和DOM型XSS更大。存储型XSS攻击的原因仍然是没有做好数据过滤:前端提交数据至服务端时,没有做好过滤;服务端在接受到数据时,在存储之前,没有做过滤;前端从服务端请求到数据,没有过滤输出。
存储型 XSS 的攻击步骤:
- 攻击者将恶意代码提交到目标网站的数据库中。
- 用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。
- 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。
如何防范存储型XSS攻击:
- 前端数据传递给服务器之前,先转义/过滤(防范不了抓包修改数据的情况)
- 服务器接收到数据,在存储到数据库之前,进行转义/过滤
- 前端接收到服务器传递过来的数据,在展示到页面前,先进行转义/过滤
1.4 防范XSS攻击
XSS(Cross-Site Scripting)攻击是一种常见的Web应用程序安全漏洞,攻击者利用漏洞在网站上注入恶意脚本或代码,以获取用户的敏感信息或控制用户的浏览器。为了防范XSS攻击,可以采取以下方法:
- 输入检查:在用户输入数据时,对数据进行检查和过滤,过滤掉特殊字符和脚本代码。比如可以使用HTML实体编码对特殊字符进行转义,比如<转义为<。
- 输出转义:在输出数据到页面上时,对数据进行转义。比如使用HTML实体编码将特殊字符转义成文本,这样就可以避免浏览器将其解析成HTML标签。比如将<转义为<。
- CSP(Content Security Policy):设置CSP响应头,限制页面中允许加载的资源类型,禁止内联脚本执行等,这样可以减少XSS攻击的影响。
- Cookie安全策略:使用HttpOnly和Secure属性,限制Cookie只能通过HTTP协议传输,防止Cookie被盗取。
- 防止DOM操作:对于不可信的数据,应该避免直接将其插入到DOM中,可以使用textContent或者innerText等属性插入数据,这样可以避免执行脚本。
- HTTPS传输:使用HTTPS协议传输数据,加密传输数据,防止数据被拦截和篡改。
- 前端框架的防护:一些前端框架(如Angular、React、Vue等)在渲染模板时会自动转义输出的内容,可以减少XSS攻击的风险。
综上所述,防范XSS攻击需要综合采用多种方法,不同的方法可以在不同的层面上增强网站的安全性。
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提交等等(来源不明的链接,不要点击)
CSRF 攻击防御
1. 添加验证码(体验不好)
验证码能够防御CSRF攻击,但是我们不可能每一次交互都需要验证码,否则用户的体验会非常差,但是我们可以在转账,交易等操作时,增加验证码,确保我们的账户安全。
2. 判断请求的来源:检测Referer(并不安全,Referer可以被更改)
1 | `Referer` 可以作为一种辅助手段,来判断请求的来源是否是安全的,但是鉴于 `Referer` 本身是可以被修改的,因为不能仅依赖于 `Referer` |
3. 使用Token(主流)
1 | CSRF攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个CSRF攻击者无法获取到的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
1 | if ( 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加载的页面地址