XSS
全称Cross Site Scripting,名为跨站脚本攻击。为啥不是单词第一个字母组合CSS,大概率与样式名称css进行区分。
XSS攻击原理
不需要你做任何的登录认证,它会通过合法的操作(比如在url中输入、在评论框中输入),向你的页面注入脚本(可能是js、html代码块等)。
导致的结果可能是:
- 破坏页面的正常结构
- 插入广告等恶意内容
- 盗用Cookie
常见的攻击方式
-
反射型
发出请求时,XSS代码出现在url中,作为输入提交到服务器端,服务器端解析后响应,XSS代码随响应内容一起传回给浏览器,最后浏览器解析执行XSS代码。这个过程像一次反射,所以叫反射型XSS。
示例:
用户A访问安全网站B,然后用户C发现B网站存在XSS漏洞,此时用户C向A发送了一封邮件,里面有包含恶意脚本的URL地址(此URL地址还是网站B的地址,只是路径上有恶意脚本),当用户点击访问时,因为网站B中cookie含有用户的敏感信息,此时用户C就可以利用脚本在受信任的情况下获取用户A的cookie信息,以及进行一些恶意操作。 -
存储型
存储型XSS和反射型XSS的差别在于,提交的代码会存储在服务器端(数据库、内存、文件系统等),下次请求时目标页面时不用再提交XSS代码。
示例:
假设网站B是一个博客网站,恶意用户C在存在XSS漏洞的网站B发布了一篇文章,文章中存在一些恶意脚本,例如img标签、script标签等,这篇博客必然会存入数据库中,当其他用户访问该文章时恶意脚本就会执行,然后进行恶意操作。即将携带脚本的数据存入数据库,之后又由后台返回。
预防措施
- 对输入、输出结果进行必要的转义和过滤
- 尽量使用post,使用get方式时对路径长度进行限制
- 使用
httponly
禁止黑客通过脚本获取用户cookie数据,但这样无法完全阻止xss攻击,因为发送http请求并不需要主动获取cookie
对输入、输出结果进行必要的转义和过滤讲解
-
编码:
对用户输入的数据进行 HTML Entity 编码。
HTML 实体是一段以连字号(&)开头、以分号(;)结尾的文本(字符串)。实体常常用于显示保留字符(这些字符会被解析为 HTML 代码)和不可见的字符(如“不换行空格”)。你也可以用实体来代替其他难以用标准键盘键入的字符。
- 不可分的空格:
- <(小于符号):
<
- >(大于符号):
>
- &(与符号):
&
- ″(双引号):
"
- '(单引号):
'
- ©(版权符号):
©
以上列出的一些实体比较容易记忆,但有一些不容易记住的您可以查看 whatwg 或使用解码工具。
在前端,一般为了避免 XSS 攻击,会将 <> 编码为
<
与>
,这些就是 HTML 实体编码。在 HTML 转义时,仅仅只需要对六个字符进行编码:&、<、>、"、’ 和 `。我们可以使用 he 库进行编码及转义,html会正常显示经实体编码或转义后的特殊字符。
// 实体编码 he.encode('<img src=""></img>') // <img src=""></img> // 实体转义 he.escape('<img src=""></img>') // <img src=""></img>
示例:
document.write('<script>alert(1)</script>')
若不进行任何处理,则浏览器会执行alert的js操作,实现XSS注入。
进行编码处理之后,在浏览器中的显示结果就是<script>alert(1)</script>
实现了作为纯文本进行输出,且不引起JavaScript的执行。
- 不可分的空格:
-
过滤:
移除用户输入的和事件相关的属性。如onerror可以自动触发攻击,还有onclick等。(总而言是,过滤掉一些不安全的内容)移除用户输入的Style节点、Script节点、Iframe节点。(尤其是Script节点,它是支持跨域的,一定要移除)。
-
校正:
避免直接对HTML Entity进行解码。使用DOM Parse转换,校正不配对的DOM标签。备注:我们应该去了解一下 DOM Parse 这个概念,它的作用是把文本解析成DOM结构。
比较常用的做法是,通过第一步的编码转成文本,然后第三步转成DOM对象,然后经过第二步的过滤。
还有一种简洁的方式: 对特定字符做相应的转义,如果是富文本,就白名单。
CSRF
全称 cross-site request forgery,名为跨站请求伪造,顾名思义就是黑客伪装成用户身份来执行一些非用户自愿的恶意以及非法操作。注意,获取cookie是XSS做的事,CSRF的作用是借用cookie,并不能获取cookie。
CSRF攻击原理
用户是网站A的注册用户,且登录进去,于是网站A就给用户下发cookie。
从上图可以看出,要完成一次CSRF攻击,受害者必须满足两个必要的条件:
-
登录受信任网站A,并在本地生成Cookie。(如果用户没有登录网站A,那么网站B在诱导的时候,请求网站A的api接口时,会提示你登录)
-
在不登出A的情况下,访问危险网站B(其实是利用了网站A的漏洞)。
我们在讲CSRF时,一定要把上面的两点说清楚。
温馨提示一下,cookie保证了用户可以处于登录状态,但网站B其实拿不到 cookie。
常见攻击情景
用户A经常访问博客网站B,用户C发现网站B存在CSRF漏洞,想尽了各种办法勾引用户A访问了C写好的危险网站D,而此时用户A的cookie信息还没有失效,危险网站D中有向网站B求请求的非法操作,这样用户在不知情的情况下就被操控了。
这个时候就会有一个疑问,浏览器本身有同源策略啊,为什么在网站D还可以请求网站B的api,要记住浏览器对img、iframe和script的src是没有同源限制的!所以黑客完全可以利用动态添加这些标签的方法来实现跨站请求。
预防措施:
-
判断请求的
Referer
是否正确:referer 指的是页面请求来源。意思是,只接受本站的请求,服务器才做响应;如果不是,就拦截。 -
设置cookie的
SameSite
SameSite
有3个值:Strict
,Lax
和None
Strict
。浏览器会完全禁止第三方cookie。比如a.com的页面中访问 b.com 的资源,那么a.com中的cookie不会被发送到 b.com服务器,只有从b.com的站点去请求b.com的资源,才会带上这些CookieLax
。相对宽松一些,在跨站点的情况下,从第三方站点链接打开和从第三方站点提交 Get方式的表单这两种方式都会携带Cookie。但如果在第三方站点中使用POST方法或者通过 img、Iframe等标签加载的URL,这些场景都不会携带Cookie。None
。任何情况下都会发送 Cookie数据
-
Token 验证
token不是为了防止XSS的,而是为了防止CSRF的。CSRF攻击的原因是浏览器会自动带上cookie,而不会带上token。
- 服务器发送给客户端一个token。
- 客户端提交的表单中带着这个token,也可以把 token 隐藏在 http 的 header头中。
- 如果这个 token 不合法,那么服务器拒绝这个请求。
攻击示例
- cookie:用户点击了链接,cookie未失效,导致发起请求后后端以为是用户正常操作,于是进行扣款操作;
- token:用户点击链接,由于浏览器不会自动带上token,所以即使发了请求,后端的token验证不会通过,所以不会进行扣款操作;
CSRF和XSS的区别
- CSRF需要登陆后操作,XSS不需要
- CSRF是请求页面api来实现非法操作,XSS是向当前页面植入js脚本来修改页面内容。