网络安全系列之前端常见的 Web 安全攻防解析
yuanyuanbyte opened this issue · 0 comments
本系列的主题是网络安全,每期讲解一个技术要点。如果你还不了解各系列内容,文末点击查看全部文章,点我跳转到文末。
如果觉得本系列不错,欢迎 Star,你的支持是我创作分享的最大动力。
常见的 Web 安全攻防解析,前端开发的你不来了解一下嘛~
随着互联网的高速发展,信息安全问题已经成为企业最为关注的焦点之一,而前端又是引发企业安全问题的高危据点。在移动互联网时代,前端人员除了传统的 XSS、CSRF 等安全问题之外,又时常遭遇网络劫持、非法调用 API 等新型安全问题。当然,浏览器自身也在不断在进化和发展,不断引入 CSP、Same-Site Cookies 等新技术来增强安全性,但是仍存在很多潜在的威胁,这需要前端技术人员不断进行“查漏补缺”。
在互联网时代,数据安全与个人隐私受到了前所未有的挑战,各种新奇的攻击技术层出不穷。如何才能更好地保护我们的数据?本文主要侧重于分析几种常见的攻击的类型以及防御的方法。
XSS
XSS
全称是 Cross Site Scripting(即跨站脚本攻击)
,是一种代码注入攻击。为了和 CSS 区分,故叫它XSS
。攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。利用这些恶意脚本,攻击者可获取用户的敏感信息等,进而危害数据安全。
对用户造成的危害如:
- 窃取Cookie。
- 监听用户行为,比如输入账号密码后直接发送到黑客服务器。
- 修改 DOM 伪造登录表单。
- 在页面中生成浮窗广告。
XSS 的本质是:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。
XSS 攻击的三种方式
通常情况,XSS 攻击的实现有三种方式——反射型、存储型和DOM型。
反射型 XSS(非持久型 XSS)
攻击者事先制作好攻击链接,需要诱导欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。
用户点击攻击链接将一段含有恶意代码的请求提交给 Web 服务器,Web 服务器接收到请求时,又将恶意代码反射给了浏览器端。用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
反射型 XSS 漏洞常见于通过 URL 传递参数的功能,如网站搜索、跳转等。
由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击。
存储型 XSS(持久型 XSS)
储存型XSS会把用户输入的数据“储存”在服务器端。
它是最危险的一种跨站脚本,相比反射型XSS和DOM型XSS具有更高的隐蔽性,所以危害更大,因为它不需要用户手动触发。允许用户存储数据的web程序都可能存在存储型XSS漏洞,当攻击者提交一段XSS代码后,被服务器端接收并存储,当所有浏览者访问这个页面时都会被XSS攻击,这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、评论、用户私信等。
DOM型 XSS
基于 DOM 的 XSS 攻击是不牵涉到页面 Web 服务器的。
在 Web 资源传输过程或者在用户使用页面的过程中修改 Web 页面的数据。
比如在数据传输过程劫持到网络数据包,然后修改里面的 html 文档!这样的劫持方式包括WIFI路由器劫持或者本地恶意软件等。
如何预防 XSS 攻击
利用 CSP
CSP 内容安全策略
,它的核心**就是服务器决定浏览器加载哪些资源。我们只需要配置规则,如何拦截是由浏览器自己实现的。
可以设置 HTTP Header 中的 Content-Security-Policy
来开启 CSP
这里以设置 HTTP Header 来举例:
- 只允许加载本站资源
Content-Security-Policy: default-src 'self'
- 只允许加载 HTTPS 协议图片
Content-Security-Policy: img-src https://*
通过CSP可以:
- 限制加载其他域下的资源文件,这样即使黑客插入了一个 JavaScript 文件,这个 JavaScript 文件也是无法被加载的;
- 禁止向第三方域提交数据,这样用户数据也不会外泄;
- 禁止执行内联脚本和未授权的脚本
输入过滤或转码
服务端将一些关键的字符进行转码,比如 <script
等
纯前端渲染
不采用服务端渲染,改成纯前端渲染,把代码和数据分隔开。
在纯前端渲染中,我们会明确的告诉浏览器:下面要设置的内容是文本(.innerText
),还是属性(.setAttribute
),还是样式(.style
)等等。浏览器不会被轻易的被欺骗,执行预期外的代码了。
HttpOnly Cookie
这是预防XSS攻击窃取用户cookie最有效的防御手段。Web应用程序在设置cookie时,将其属性设为HttpOnly,浏览器会禁止页面的JS访问带有HttpOnly属性的Cookie。这样就可以避免该网页的cookie被客户端恶意JavaScript窃取,保护用户cookie信息。
CSRF
CSRF(Cross Site Request Forgery
),即跨站请求伪造,是一种常见的Web攻击,它利用用户已登录的身份,在用户毫不知情的情况下,以用户的名义完成非法操作。
CSRF攻击的原理(建议详读下图)
:
从上图我们可以知道CSRF攻击的流程:
- 用户登录了信任网站A,并保留了登录凭证(Cookie);
- 在用户没有登出 A网站 的情况下(也就是 cookie 生效的情况下),攻击者引诱受害者访问了 危险网站B;
- 危险B网站 向 A网站 发送了一个请求;
- A网站 接收到请求后,对请求进行验证,并确认是用户的凭证,误以为是用户自己发送的请求
- A网站 以用户的名义执行了操作。
- 攻击者在用户不知情的情况下,冒充用户,让 A网站 执行了自己定义的操作,攻击完成。
常见的 CSRF 攻击类型
自动发送 GET 请求的 CSRF
GET类型的CSRF利用非常简单,只需要一个HTTP请求,一般会这样利用:
<img src="http://bank.example/withdraw?amount=10000&for=hacker" >
在用户访问含有这个img的页面后,浏览器会自动向http://bank.example/withdraw?account=xiaoming&amount=10000&for=hacker
发出一次HTTP请求。bank.example
就会收到包含用户登录信息的一次跨域请求。
自动发送 POST 请求的 CSRF
这种类型的CSRF利用起来通常使用的是一个自动提交的表单,如:
<form action="http://bank.example/withdraw" method=POST>
<input type="hidden" name="account" value="xiaoming" />
<input type="hidden" name="amount" value="10000" />
<input type="hidden" name="for" value="hacker" />
</form>
<script> document.forms[0].submit(); </script>
访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。
POST类型的攻击通常比GET要求更加严格一点,但仍并不复杂。任何个人网站、博客,被黑客上传页面的网站都有可能是发起攻击的来源,后端接口不能将安全寄托在仅允许POST上面。
诱导点击发送 GET 请求 的 CSRF
链接类型的CSRF并不常见,比起其他两种用户打开页面就中招的情况,这种需要用户点击链接才会触发。这种类型通常是在论坛中发布的图片中嵌入恶意链接,或者以广告的形式诱导用户中招,攻击者通常会以比较夸张的词语诱骗用户点击,例如:
<a href="http://test.com/csrf/withdraw.php?amount=1000&for=hacker" taget="_blank">
重磅消息!!
<a/>
由于之前用户登录了信任的网站A,并且保存登录状态,只要用户主动访问上面的这个PHP页面,则表示攻击成功。
如何预防 CSRF 攻击
同源检测
既然 CSRF 攻击大多来自第三方网站,那么我们就直接禁止外域(或者不受信任的域名)对我们发起请求,从而阻止 CSRF 攻击。
那么问题来了,我们如何判断请求是否来自外域呢?利用 HTTP 请求头中的 Referer 和 Origin 属性。
优先判断 Origin,如果请求头中没有包含 Origin 属性,再根据实际情况判断是否使用 Referer 值。
这两个Header在浏览器发起请求时,大多数情况会自动带上,并且不能由前端自定义内容。
服务器可以通过解析这两个Header中的域名,确定请求的来源域。
CSRF Token
讲到CSRF的一个特征是,攻击者无法直接窃取到用户的信息(Cookie,Header,网站内容等),仅仅是冒用Cookie中的信息。
而CSRF攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个CSRF攻击者无法获取到的Token。服务器通过校验请求是否携带正确的Token,来把正常的请求和攻击的请求区分开,也可以防范CSRF的攻击。
利用Cookie的SameSite属性
CSRF
攻击中重要的一环就是自动发送目标站点下的 Cookie
,就是这一份 Cookie
模拟了用户的身份。为了从源头上解决这个问题,可以为Set-Cookie
响应头设置Samesite
属性,它用来标明这个 Cookie是个“同站 Cookie”。
Set-Cookie: foo=1; Samesite=Strict
Set-Cookie: bar=2; Samesite=Lax
Set-Cookie: baz=3
SameSite
可以设置为三个值,Strict
、Lax
和None
。
Strict
:严格模式,浏览器完全禁止第三方请求携带Cookie。比如请求sanyuan.com网站只能在sanyuan.com域名当中请求才能携带 Cookie,在其他网站请求都不能。Lax
:宽松模式,仅在顶部窗口导航(例如<a>标签、window.open()
)中的GET请求中发送 cookie 。这是浏览器中的默认值。None
,请求会自动携带上 Cookie。以前 None 是默认值,但最近的浏览器版本将 Lax 作为默认值,以便对某些类型的跨站请求伪造 (CSRF) 攻击具有相当强的防御能力。
注意!!!
使用该方法的问题是Samesite的兼容性不是很好,现阶段除了从新版Chrome和Firefox支持以外,Safari以及iOS Safari都还不支持,现阶段看来暂时还不能普及。
而且,SamesiteCookie目前有一个致命的缺陷:不支持子域。例如,种在topic.a.com下的Cookie,并不能使用a.com下种植的SamesiteCookie。这就导致了当我们网站有多个子域名时,不能使用SamesiteCookie在主域名存储用户登录信息。每个子域名都需要用户重新登录一次。
总之,SamesiteCookie是一个可能替代同源验证的方案,但目前还并不成熟,其应用场景有待观望。
验证码
应用程序和用户进行交互过程中,特别是账户交易这种核心步骤,强制用户输入验证码,才能完成最终请求。在通常情况下,验证码够很好地遏制CSRF攻击。但增加验证码降低了用户的体验,网站不能给所有的操作都加上验证码。所以只能将验证码作为一种辅助手段,在关键业务点设置验证码。
参考
- https://juejin.cn/post/6844903685122703367
- https://juejin.cn/post/6844903639820009486
- https://juejin.cn/post/6844903502968258574
- https://juejin.cn/post/6844903502968258574
- https://juejin.cn/post/6994747063976067086
- https://juejin.cn/post/6844903772930441230
- https://juejin.cn/post/6844904021308735502
- https://www.jianshu.com/p/4fcb4b411a66
- https://www.jianshu.com/p/790fb57f3acb
- https://juejin.cn/post/6994747063976067086#heading-28
- https://zhuanlan.zhihu.com/p/354215929
- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Set-Cookie/SameSite
博文系列目录
- JavaScript 深入系列
- JavaScript 专题系列
- JavaScript 基础系列
- 网络系列
- 浏览器系列
- Webpack 系列
- Vue 系列
- 性能优化与网络安全系列
- HTML 应知应会系列
- CSS 应知应会系列
交流
各系列文章汇总:https://github.com/yuanyuanbyte/Blog
我是圆圆,一名深耕于前端开发的攻城狮。