XSS 攻击
什么是 XSS 攻击
XSS 即 Cross Site Scripting(跨站脚本攻击),指的是攻击者想尽一切办法将一些可执行的代码注入到网页中,利用这些恶意脚本,攻击者可获取用户的敏感信息如 Cookie、SessionID 等,进而危害数据安全。为了不和层叠样式表 CSS 混淆,故将其缩写为 XSS
XSS 可以分为:存储型 XSS (也叫持久型 XSS)、反射型 XSS (也叫非持久型)。
存储型
存储型也就是攻击的代码被服务端写入进数据库中,这种攻击危害性很大,因为如果网站访问量很大的话,就会导致大量正常访问页面的用户都受到攻击。
这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。具有攻击性的脚本被保存到了服务器并且可以被普通用户完整的从服务的取得并执行,从而获得了在网络上传播的能力。
反射型
反射型也叫非持久型,相比于前者危害就小一些,一般通过修改 URL 参数的方式加入攻击代码,诱导用户访问链接从而进行攻击。
这种常见于通过 URL 传递参数的功能,如网站搜索、跳转等。由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击。
二者区别:存储型 XSS 的恶意代码存在数据库里,反射型 XSS 的恶意代码存在 URL 里。
举两个案例帮助更好的理解:当我们在做商品评论时,用户输入的内容未经过过滤直接保存到数据库中。
攻击者可以构建一条评论, 包含恶意内容:
质量非常不错!
当你的评论列表被用户浏览时, 直接从服务端取出,回填到 HTML 响应中:
质量非常不错!
那么浏览器会加载执行恶意脚本 danger.com/spread.js, 在恶意脚本中利用用户的登录状态发更多的带有恶意评论的 URL, 诱导更多人点击,层层传播,放大攻击范围。
这个案例就是一个典型的存储型 XSS 攻击。再来看一个反射型攻击案例:
某天小范开发了一个搜索页面,通过用户输入搜索内容,展示相应的数据:
http://localhost:8080/helloController/search?name=
http://localhost:8080/helloController/search?name=
http://localhost:8080/helloController/search?name=点我
有时攻击者会伪造一个图片,让你点击后链接跳转 URL。
对于这种攻击方式来说,如果用户使用的是 Chrome 浏览器的话,浏览器已经帮助用户做了防御攻击。但是我们也不能说就不防御了,因为无法保证用户都是用有防御攻击的浏览器。
XSS 攻击如何进行防范
- 输入输出过滤
一切用户输入皆不可信,在输出时进行验证,一般做法是将 ‘ ” < > & 这些个危险字符进行转义。
const signs = {
"&": "&",
"<": "<",
">": ">",
'"': """,
"'": "'",
};
const signReg = /[&<>"']/g;
function escape(string) {
return string && reUnescapedHtml.test(string)
? string.replace(reUnescapedHtml, (chr) => htmlEscapes[chr])
: string;
}
通过转义 将被转义成
<script></script>
;
对于 URL 地址的转义可以使用
encodeURI
,当你需要编码 URL 中的参数的时候,那么encodeURIComponent
是最好方法。
上面对字符进行转义的方式很明显并不适用于所有场景,比如富文本,这样会将需要的格式都过滤掉。因为 HTML 标签种类繁多,基于黑名单的过滤方法考虑的并不全面,所以我们可以根据白名单过滤 HTML, 可以借助 xss.js
来完成:
// 浏览器
使用:
filterXSS('XSS Demo
Whitelist
')
输出结果:
XSS Demo
<script type="text/javascript">alert(/xss/);</script>
Whitelist
如果后端直接将字符串存入数据库也是不妥的,后端也必须做处理,因为发送到后端的内容还可以通过其他方式, 前端处理并不能保障安全。
- Cookie 的 HttpOnly
当用户的登录凭证存储于服务器的 session 中,而在浏览器中是以 cookie 的形式存储的。很多 XSS 攻击目标都是窃取用户 cookie 伪造身份认证。
可以通过在 cookie 中设置 HttpOnly 属性,js 脚本将无法读取到 cookie 信息。
ctx.cookies.set(name, value, {
httpOnly: true, // 默认为 true
});
- CSP(内容安全策略)
CSP (Content Security Policy,内容安全策略)是 W3C 提出的 ,本质上就是白名单制度,开发者明确告诉浏览器哪些外部资源可以加载和执行。它的实现和执行全部由浏览器完成,我们只需提供配置。
CSP 大大增强了网页的安全性。攻击者即使发现了漏洞,也没法注入脚本,除非还控制了一台列入了白名单的可信主机。
两种方法可以启用 CSP:
- 一种是通过 HTTP 头信息的 Content-Security-Policy 的字段
- 另一种是通过网页的
标签
方式 1 举例
Content-Security-Policy: default-src ‘self’
表示只允许加载本站资源
Content-Security-Policy: default-src https://demo.example.cn https://demo.example2.cn; object-src 'none'
CSP 的值中,不同属性以 ; 隔开,同一属性的多个值以空格隔开。上面例子的意思就是默认允许读取 https://demo.example.cn和https://cdn.example2.net 的资源,object-src 使用的相关资源无白名单,也就是完全不允许读出。
如果使用了不符合要求的资源,浏览器会给予拦截,给出下面提示:
Refused to execute inline script because it violates the following Content Security Policy directive
我们也可以使用 meta 标签代替 HTTP 头:
Content-Security-Policy 的常用选项有这些:
- default-src: 是 src 选项的默认值,但不能覆盖以下值:base-uri、form-action、frame-ancestors、plugin-types、report-uri、sandbox
- base-uri:特别说一下
标签是因为孤陋寡闻的我第一次见到。指定用于一个文档中包含的所有相对 URL 的根 URL,一个文件只能有一个
标签,用起来大概是这样的:
。 - connect-src: XHR、WebSockets 等连接使用的地址
- font-src:字体文件来源
- img-src:图片地址
- media-src:音视频地址
- object-src:Flash 相关
- report-uri:出现报错时提交到指定 uri,不能在 标签使用
- style-src:样式文件
CSRF 攻击
除了上面说的 XSS 攻击外,还有一种常见的攻击方式:CSRF 攻击。
什么是 CSRF 攻击
CSRF:跨站点请求伪造(Cross-Site Request Forgeries),也被称为 one-click attack 或者 session riding。冒充用户发起请求(在用户不知情的情况下), 完成一些违背用户意愿的事情(如修改用户信息,删除评论等)。
举个例子,好友小 A 在银行存有一笔钱,输入用户名密码登录银行账户后,发送请求给 xiaofan 账户转 888:
http://bank.example.com./withdraw?account=xiaoA&amount=888&for=xiaonfan
转账过程中, 小 A 不小心打开了一个新页面,进入了黑客(xiaohei)的网站,而黑客网站有如下 html 代码:
这个模拟的 img 请求就会带上小 A 的 session 值, 成功的将 888 转到 xiaohei 的账户上。例子虽然是 get,post 请求提交表单同样会被攻击。
CSRF 攻击的特点:
- 通常发生在第三方网站
- 攻击者不能获取 cookie 等信息,只是使用
如何防御
- 验证码:强制用户必须与应用进行交互,才能完成最终请求。此种方式能很好的遏制 CSRF,但是用户体验相对差。
- 尽量使用 post ,限制 get 使用;上一个例子可见,get 太容易被拿来做 CSRF 攻击,但是 post 也并不是万无一失,攻击者只需要构造一个 form 就可以。
- Referer check:请求来源限制,此种方法成本最低,但是并不能保证 100% 有效,因为服务器并不是什么时候都能取到 Referer,而且低版本的浏览器存在伪造 Referer 的风险。
- token:token 验证的 CSRF 防御机制是公认最合适的方案。
CSRF 与 XSS 区别
通常来说 CSRF 是由 XSS 实现的,CSRF 时常也被称为 XSRF(CSRF 实现的方式还可以是直接通过命令行发起请求等)。
本质上讲,XSS 是代码注入问题,CSRF 是 HTTP 问题。XSS 是内容没有过滤导致浏览器将攻击者的输入当代码执行。CSRF 则是因为浏览器在发送 HTTP 请求时候自动带上 cookie,而一般网站的 session 都存在 cookie 里面。XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。
点击劫持
点击劫持(click hijacking)也称为 UI 覆盖攻击。它通过一些内容(如游戏)误导被攻击者点击,虽然被攻击者点击的是他所看到的网页,但其实所点击的是另一个置于原网页上面的透明页面。
根据先点击劫持原理示意图,分析典型点击劫持攻击流程:
- 攻击者构建了一个非常有吸引力的网页
- 将被攻击的页面放置在当前页面的 iframe 中
- 使用样式将 iframe 叠加到非常有吸引力内容的上方
- 将 iframe 设置为 100%透明
- 用户在不知情的情况下点击按钮,触发执行一些其他命令。
如何防御
点击劫持攻击需要首先将目标网站载入到恶意网站中,使用 iframe 载入网页是最有效的方法。
所以可以设置我们的网页不允许使用 iframe 被加载到其他网页中就可以避免这种情况了,我们可以通过在响应头中设置 X-Frame-Options(服务器端进行),X-Frame-Options 可以设置以下三个值:
- DEBY:不允许任何网页使用 iframe 加载我这个页面。
- SAMEORIGIN:只允许在相同域名(也就是自己的网站)下使用 iframe 加载这个页面。
- ALLOWED-FROM origin: 允许任何网页通过 iframe 加载我这个网页。
这种方式在一些老旧的浏览器上是不支持的,具体可以通过 can i use
去查看
中间人攻击
中间人(Man-in-the-middle attack, MITM)是指攻击者和通讯的两端分别创建独立的联系,并交换其得到的数据,攻击者可以拦截通信双方的通话并插入新的内容。
一般的过程如下:
- 客户端发送请求到服务端,请求被中间⼈截获
- 服务器向客户端发送公钥
- 中间⼈截获公钥,保留在⾃⼰⼿上。然后⾃⼰⽣成⼀个【伪造的】公钥,发给客户端
- 客户端收到伪造的公钥后,⽣成加密 hash 值发给服务器
- 中间⼈获得加密 hash 值,⽤⾃⼰的私钥解密获得真秘钥,同时⽣成假的加密 hash 值,发给服务器
- 服务器⽤私钥解密获得假密钥,然后加密数据传输给客户端
如何防御
采用 HTTPS 通信可以防御中间人攻击, 但是使用 HTTPS 并不就绝对安全,一方面你要完全关闭 HTTP 通信,如果没有完全关闭,攻击者可以通过某些方式将 HTTPS 降级为 HTTP,从而实现中间人攻击。
其次使用 HTTPS 通信,开发时也不要忽视证书的校验,或者对于非法证书不进行处理,这样也容易被中间人攻击。
为什么有些软件如 Fiddler 可以还原 https 报文?
Fiddler 是通过中间代理的方式抓取报文,还原 https 报文的前提是在客户端的根证书列表下加入 Fiddler 生成的 CA 根证书。这样 Fiddler 就成为 CA,可以伪造数字证书,伪装成服务器。但是只能用于测试,不能实现真正意义上的窃取数据。
原文链接:你在项目中做过哪些安全防范措施?