# 前端安全
前端安全分两类:CSRF、XSS
# XSS
XSS(Cross-Site Scripting,跨站脚本攻击
)是一种代码注入攻击。攻击者在目标网站上注入恶意代码,当被攻击者登陆网站时就会执行这些恶意代码,这些脚本可以读取 cookie,session tokens,或者其它敏感的网站信息,对用户进行钓鱼欺诈,甚至发起蠕虫攻击等。
这些操作一般可以完成下面这些事情:
- 窃取Cookie。
- 监听用户行为,比如输入账号密码后直接发送到黑客服务器。
- 修改 DOM 伪造登录表单。
- 在页面中生成浮窗广告。
通常情况,XSS 攻击的实现有三种方式——存储型、反射型和文档型。原理都比较简单,先来一一介绍一下。
# 存储型
顾名思义就是将恶意脚本存储了起来,确实,存储型的 XSS 将脚本存储到了服务端的数据库,然后在客户端执行这些脚本,从而达到攻击的效果。
常见的场景是留言评论区提交一段脚本代码,例如:
<script src="http://恶意网站"></script><iframe></iframe>
如果前后端没有做好转义的工作,那评论内容存到了数据库,在页面渲染过程中直接执行
, 相当于执行一段未知逻辑的 JS 代码,是非常恐怖的。
# 反射型
反射型XSS
指的是恶意脚本作为网络请求的一部分。
比如我输入:
http://sanyuan.com?q=<script>alert("你完蛋了")</script>
这样,在服务器端会拿到q
参数,然后将内容返回给浏览器端,浏览器将这些内容作为HTML的一部分解析,发现是一个脚本,直接执行,这样就被攻击了。
思路肯定是没问题的,不过你可能会发现不起效果,这是因为浏览器针对script等一些危险标签的插入做了拦截过滤,当然了这难不倒我们,毕竟咱们也不能把我要干坏事写在脸上,这不尊重对手,所以咱们换种委婉一点的写法就行了:
http://sanyuan.com?q=<img src="" onerror="alert(document.cookie)" />
因为是插入一张图片,浏览器一般不会过滤拦截,然后我们把src置空使其触发onerror
事件,间接地执行我们的恶意脚本。done!
之所以叫它反射型
,是因为恶意脚本是通过作为网络请求的参数,经过服务器,然后再反射到HTML文档中,执行解析。
Web 服务器不会存储反射型 XSS 攻击的恶意脚本,这是和存储型 XSS 攻击不同的地方。
# 文档型
文档型的 XSS 攻击并不会经过服务端,而是作为中间人的角色,在数据传输过程劫持到网络数据包,然后修改里面的 html 文档!
DOM 型 XSS 攻击,实际上就是前端JavaScript
代码不够严谨,把不可信的内容插入到了页面。在使用 .innerHTML
、.outerHTML
、.appendChild
、document.write()
等API时要特别小心,不要把不可信的数据作为 HTML 插到页面上,尽量使用.innerText
、.textContent
、.setAttribute()
等。
# 防范措施
明白了三种XSS攻击的原理,我们能发现一个共同点:都是让恶意脚本直接能在浏览器中执行。
那么要防范它,就是要避免这些脚本代码的执行。
- 无论是在前端和服务端,都要对用户的输入进行转码或者过滤。
function escape(str) {
str = str.replace(/&/g, '&');
str = str.replace(/</g, '<');
str = str.replace(/>/g, '>');
str = str.replace(/"/g, '&quto;');
str = str.replace(/'/g, '&##39;');
str = str.replace(/`/g, '&##96;');
str = str.replace(/\//g, '&##x2F;');
return str;
}
// 通过转义,将攻击代码变成
escape('<script>alert(1)</script>');
// <script>alert(1)<&##x2F;script>
- 净化和过滤掉不必要的html标签,比如:
<iframe>
,<script>
等; - 净化和过滤掉不必要的Javascript的事件标签,比如:
onclick
,onfocus
等 - 转义单引号,双引号,尖括号等特殊字符,可以采用htmlencode编码 或者过滤掉这些特殊字符
- HttpOnly
很多XSS攻击脚本都是用来窃取Cookie
, 而设置Cookie
的HttpOnly
属性后,禁止Javascript通过document.cookie
获得Cookie
的值。
- CSP
在服务端使用 HTTP 的Content-Security-Policy
头部来指定策略,或者在前端设置meta
标签。
例如下面的配置只允许加载同域下的资源:
<!-- 1. http 头部 -->
Content-Security-Policy: default-src 'self'
<!-- 2. meta -->
<meta http-equiv="Content-Security-Policy" content="form-action 'self'">
严格的 CSP 在 XSS 的防范中可以起到以下的作用:
- 限制其他域下的资源加载。
- 禁止向其它域提交数据。
- 禁止内联脚本执行(规则较严格,目前发现 GitHub 使用)。
- 禁止未授权的脚本执行(新特性,Google Map 移动版在使用)。
- 合理使用上报可以及时发现 XSS,利于尽快修复问题。
- 对于url链接(例如图片的src属性),那么直接使用
encodeURIComponent
来转义。
# CSRF
CSRF(Cross-site request forgery), 即跨站请求伪造
。指的是黑客诱导用户点击链接,打开黑客的网站,然后黑客利用用户目前的登录状态发起跨站请求。
要完成一次CSRF攻击,受害者必须依次完成两个步骤:
- 受害者登录A站点,并保留了登录凭证(Cookie)。
- 攻击者诱导受害者访问了站点B。
- 站点B向站点A发送了一个请求,浏览器会默认携带站点A的Cookie信息。
- 站点A接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是无辜的受害者发送的请求。
- 站点A以受害者的名义执行了站点B的请求。
- 攻击完成,攻击者在受害者不知情的情况下,冒充受害者完成了攻击。
- 跨站请求可以用各种方式:图片URL、超链接、CORS、Form提交等等(来源不明的链接,不要点击)
# 防范措施
- Cookie的SameSite属性
CSRF攻击中重要的一环就是自动发送目标站点下的Cookie
,然后就是这一份Cookie
模拟了用户的身份。因此在Cookie
上面下文章是防范的不二之选。
SameSite
可以设置为三个值,Strict
、Lax
和None
。
- 在
Strict
模式下,浏览器完全禁止第三方请求携带Cookie
。比如请求sanyuan.com
网站只能在sanyuan.com
域名当中请求才能携带Cookie
,在其他网站请求都不能。 - 在
Lax
模式,就宽松一点了,但是只能在get
方法提交表单况或者a标签发送get
请求的情况下可以携带Cookie
,其他情况均不能。 - 在
None
模式下,也就是默认模式,请求会自动携带上 Cookie。
- Token验证(主流)
- 服务端给用户生成一个
token
,加密后传递给用户 - 用户在提交请求时,需要携带这个
token
- 服务端验证
token
是否正确
- Referer 验证
Referer
可以作为一种辅助手段,来判断请求的来源是否是安全的,但是鉴于 Referer
本身是可以被修改的,因此不能仅依赖于 Referer
- 二次验证
针对一些有危险性的请求操作(比如删除账号,提现转账)我们可以增加用户的二次,比如发起手机或者邮箱验证码检验,进而降低CSRF打来的危害。
# 文件上传漏洞
服务器未校验上传的文件,致使黑客可以上传恶意脚本等方式。
- 用文件头来检测文件类型,使用白名单过滤(有些文件可以从其中一部分执行,只检查文件头无效,例如 PHP 等脚本语言);
- 上传后将文件彻底重命名并移动到不可执行的目录下;
- 升级服务器软件以避免路径解析漏洞;
- 升级用到的开源编辑器;
- 管理后台设置强密码。