XSS 攻击与防护
AI summary
date
Aug 13, 2024
slug
xss-effect
status
Published
tags
技术
summary
web 生存指南:永远不要相信用户的输入
type
Post
啥是 XSS ?
XSS 是 Cross Site Scripting 的缩写,意思为 “跨站脚本”。
说人话,就是让被攻击者执行一些本不属于原网站的代码。
假设我们是一个超级大黑客,如何把恶意代码携带给用户?
这是一个很有趣的问题,要解答这个问题,首先要理清我们的袭击目标的行为。

输入是我们可以蛊惑小可爱的地方,然后利用服务器和客户端代码的漏洞修改其输出,实现代码注入。

反射型 XSS
有时候,服务器返回的页面,是有用户的参数动态生成的。这就给了我门可乘之机。而如果这个参数是通过 url params 传递的,那就天助我也。

上面这个游戏可体验 XSS 攻击,他提供了一个根据用户参数动态生成页面内容的网站,并且不对输入做过滤
比如我们输入 <h1> hello </h1> ,他会在访问时携带
?search=<h1>hello</h1>


网站部分源码:
观察这里标亮的代码,会直接根据用户的参数动态生成 html,这就是这个页面的漏洞,而这个参数是通过 URL params 传递,所以我只要给 URL 中添加恶意脚本 params,用户点击就会执行
我上边留的链接:
上述的这种攻击方式,通过 params 参数,输入给服务器,在服务器输出含有恶意代码的 html,被称为反射 XSS。
啥?为啥叫反射?

因为他是一个自己打自己的过程,用户请求时自己携带了恶意参数(小可爱用户并没有发现),他是通过请求时携带,响应时生成,是一个非持久化的攻击方式。
存储型 XSS
我懂了,我再也不会点击别人的链接了,我无敌了。
不好意思,并不能。
只要你不乱点,黑客确实不能突破你,但他可以直接突破数据库。

体验
点击这个小游戏,可以体验 存储型 XSS 攻击

点击上方游戏链接,可以看到这是一个论坛,大家都可以发言。黑客只需要通过 “发帖子” 就能把恶意代码存到数据库,当你访问这个论坛,就会请求到黑客在此处留下的发言,然后就寄,可见,这种攻击是非常严重的,因为他是大范围被动杀伤技能。
现在我们实操一下,留言 <h1>hello</h1>

发现它渲染了,那还不简单,直接往里插 script。
但这个网站稍微聪明点,他过滤了你的 script 标签。这次并没有起效果


那就没办法攻击了吗?不是,img 标签有个 onerror 属性,在图片加载失败时就会执行其中的回调


可以看到,尽管这个网站过滤了 script 标签,但黑客利用 img 的特点(网站没有过滤 img),依旧实现了注入。
只要访问到这个帖子的人,就会执行 Img 的 onerror 回调,就会被攻击。
因为直接把恶意脚本存在了数据库,所以这种攻击叫 存储型XSS。
DOM型 XSS
前两种攻击方式,都是针对服务器,一种是利用了服务器输出时的漏洞,一种是利用数据存储时的漏洞。还有一种攻击方式,是利用客户端运行时的漏洞。
打开上面这个网址,现在你的目标是注入恶意代码,让用户访问你的 URL 时,显示一个 alert 弹窗。
先随便点点试试

当我们点击图片的 tab 时,发现图片发生了变化,同时 url 中的
#
(hash)发生了变化。关于 # 参数
params 参数,即
?
后面的参数,是会携带给服务器的。
而 hash 参数,即 #
后面的参数,是运行时参数,不会携带给服务器,通过 js 脚本访问因此可以想到,客户端脚本一定用到了 hash 参数,我们随便输入一个值试试

输入 4 后,发现确实在运行时使用了 hash 参数,通过控制台打开源码也可以看到:

前端在拼接图片地址时,使用到了 hash 的值,这就是他的漏洞,他使用了 url 参数拼接 DOM!
这还不简单,提前截断他的 img 标签并加入 onerror 事件
这个 URL 便实现了攻击,原理是,截断了原来的 img 标签拼接,插入了 onerror 事件,并将后面的代码注释
这个攻击利用了前端代码的漏洞(客户端运行时),被称为 DOM 攻击。
防御策略
网站访问与渲染的过程,本质上是一个数据输入输出的过程。
输入:
- 输入向服务器的运行时(params 参数)
- 输入向服务器的数据库(表单 参数)
- 输入向客户端的运行时 (比如 hash 参数)
输出:
- 服务器输出 (利用服务器动态生成 html 的漏洞)
- 客户端输出 (利用客户端动态生成 html 的漏洞)
因此防御的根本就是
- 预防输入:白名单过滤,清洗(转译)输入
- 预防输出:尽量避免动态生成 html ,输出用户输入时,使用安全模版编译
总结
XSS 攻击,利用了用户对网站的信任,但整个输入输出的链路上都可能发生漏洞。
web 生存指南:永远不要相信用户的输入