浅谈前端攻击
刷题时,遇到前端攻击的问题。这个也是看了一百遍忘一百遍。所以写一遍,巩固记忆。
XSS攻击
先来个简单的白话描述什么是XSS攻击
Cross-Site Scripting(跨站脚本攻击)简称 XSS
是没有过滤用户输入,而直接把用户输入插入到html中,执行不可靠代码造成损失的攻击。
如。用户在个input中输入
<script>alert('xss')</script>
如果反显时直接将上面的的用户输入innerHTML = [userinput]。那么就会在页面里插入一段js。
如果用户插入的是一段自己的远程js。那么这段远程js是可以访问当前的任何数据,包括登陆信息,这样攻击者就的js就能访问被攻击者的账户信息了。
这样就产生了一次XSS攻击。
根据分类,可以分三种类型的XSS攻击:存储型
、反射型
与DOM型
存储型
一般发生在有评论的网站。攻击者提交评论时带有攻击性的内容。在展示评论时。如果没有特殊处理,可能会被注入代码。
反射型
是攻击代码放在url中,如果没有处理,url中的代码以某种形式注入到页面中,就会被攻击。
前两者指的都是后端的锅,指的是,后端直接拼接html返回给前端造成的问题。如PHP的模板语法等。
而DOM型
指的是浏览器端不加处理插入未经处理的输入,造成的注入。
详细的看链接:前端安全系列(一):如何防止XSS攻击? - 美团技术团队
如何防范
html转义
正常情况下,需要对不可靠信息进行过滤,比如对
<script>alert('xss')</script>
转成
"><script>alert('XSS');</script>
而实际上。转义不只是转<
,>
等符号,实际情况要更复杂。应该用非常成熟的转义库操作才行。具体原因见链接。
在页面中展示是一样的
禁止危险输入
尽量不要使用 v-html/dangerouslySetInnerHTML
。React-dom的render会自动转义,不用特殊的方法就很安全。
尽量使用document.createElement
、setAttribute
等方法操作dom,不要拼接字符串然后的方法。
避免用能执行字符串代码的方法
慎用用eval
、setTimeout
、setInterval
、innerHTML
、outerHTML
、document.write
这些方法不能执行不可靠的内容。
(亲测,最新chrome已经无法用innerHTML
、document.write
插入字符串script标签
,会报Uncaught SyntaxError: Invalid or unexpected token
错误)
CSP
html头部添加CSP限制,完全禁止外域js代码加载
前后端分离
如上所说,目前新版浏览器已经禁止直接插入危险字符串(如<script>),所以前端操作dom会相对安全许多。以前的后端是直接拼接html返回给浏览器的形式,浏览器是无法识别是不是安全代码。所以危险性会高不少。所以从某种角度说,避免后端拼接html,采用前后端分离,也是防范XSS的一种方法。
日常开发
日常开发其实不太可能会遇到xss攻击
- React-dom会自动转义。只要不用innerHTML、outerHTML、document.write、eval、v-html/dangerouslySetInnerHTML插入不可靠数据即可
- 对简单的项目,加上CSP禁止外域js加载
- 禁止后端拼接html返回前端
CSRF
CSRF全称为跨站请求伪造(Cross-site request forgery)
一次经典攻击流程就是
- 小明在a网站登陆
- 小黑给小明推了个链接,小白点击链接
- 链接里包含了个自动提交的form表单,表单的提交内容即a网站的某个很有价值的链接(如转账等)此时的提交会带上小明在a网站上登陆的cookie
- 这样小明就在不知情的情况下做了对自己不利的操作。
详细的看链接:前端安全系列(二):如何防止CSRF攻击
如何防范
加上随机token
目前公司就是这么做的。原理是。在页面加载的时候,随机生成一个token传给前端,且存入session。
然后前端在每个ajax中写入该token。后端拿到该token,与session里的比对。如果匹配得上,则能证明是自己的页面发起的token。一般CSRF攻击没法访问自己页面的js环境,无法拿到token。
随机token也有自己的局限。
- 需要手动在每个ajax请求添加token
- 如果是大型分布式网站,存储token将会带来同步的问题。
- 需要消耗计算性能
校验referer
每个浏览器发起请求时,都会自动在http请求头写入参数,该参数固定是发起请求页面的协议 + 域名。后端可以判断referer是不是自己的域名,从而判断是否是自己的页面。
双从cookie
这个原理同随机token,只是不需要生成token,而是在ajax请求体中带上cookie。后端通过比对请求体中的cookie和请求头里的cookie,从而判断是不是自己的网站。因为第三方攻击网站无法访问自己网站的js环境,无法读取cookie。相对随机token好处在于省去把token存储在session造成同步session的问题和计算token产生额外消耗的问题
双重cookie的缺点在于
- cookie一般量大,造成get请求不美观。
- http请求体量大,占用带宽
samesite cookie
新浏览器新出的特性,可以让cookie只从本域名发出。
语法是
Set-Cookie: CookieName=CookieValue; SameSite=XXX;
SameSite有三个值 分别是
- Strict
- Lax
- None
Strict
完全禁止第三方cookie。比如,当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登陆状态。
Lax
规则是: 大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。
请求类型 | 示例 | 正常情况 | Lax |
---|---|---|---|
链接 | <a href=”” /> | 发送Cookie | 发送Cookie |
预加载 | <link ref=”preload” href=” /> | 发送Cookie | 发送Cookie |
GET表单 | <form method=”GET” /> | 发送Cookie | 发送Cookie |
POST表单 | <form method=”POST” /> | 发送Cookie | 不发送 |
iframe | <iframe src=”” /> | 发送Cookie | 不发送 |
ajax | – | 发送Cookie | 不发送 |
Image | <img src=”” /> | 发送Cookie | 不发送 |
基本上杜绝了CSRF攻击,注意不要用get接口写重要的逻辑就好。。
None
关闭samesite,注意必须跟着Secure使用。
Set-Cookie: widget_session=abc123; SameSite=None; Secure