跨站脚本漏洞 (XSS) 基础讲解
XSS 漏洞
一、文章简介
XSS 漏洞是 Web 应用程序中最常见的漏洞之一。如果您的站点没有预防 XSS 漏洞的固定方法,那么很可能就存在 XSS 漏洞。
这篇文章将带你通过代码层面去理解三个问题:
- 什么是 XSS 漏洞?
- XSS 漏洞有哪些分类?
- 如何防范 XSS 漏洞?
二、XSS 漏洞简介
跨站脚本攻击是指恶意攻击者往 Web 页面里插入恶意 Script 代码,当用户浏览该页之时,嵌入其中 Web 里面的 Script 代码会被执行,从而达到恶意攻击用户的目的。
xss 漏洞通常是通过 php 的输出函数将 javascript 代码输出到 html 页面中,通过用户本地浏览器执行的,所以 xss 漏洞关键就是寻找参数未过滤的输出函数。
常见的输出函数有: echo printf print print_r sprintf die var-dump var_export
.
xss 分类:(三类)
- 反射型 XSS:<非持久化> 攻击者事先制作好攻击链接, 需要欺骗用户自己去点击链接才能触发 XSS 代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。
- 存储型 XSS:<持久化> 代码是存储在服务器中的,如在个人信息或发表文章等地方,加入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,每当有用户访问该页面的时候都会触发代码执行,这种 XSS 非常危险,容易造成蠕虫,大量盗窃 cookie(虽然还有种 DOM 型 XSS,但是也还是包括在存储型 XSS 内)。
- DOM 型 XSS:基于文档对象模型 Document Objeet Model,DOM) 的一种漏洞。DOM 是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问和更新文档内容、结构和样式,处理后的结果能够成为显示页面的一部分。DOM 中有很多对象,其中一些是用户可以操纵的,如 uRI ,location,refelTer 等。客户端的脚本程序可以通过 DOM 动态地检查和修改页面内容,它不依赖于提交数据到服务器端,而从客户端获得 DOM 中的数据在本地执行,如果 DOM 中的数据没有经过严格确认,就会产生 DOM XSS 漏洞。
三、XSS 漏洞原理
3.1 反射型 XSS
在黑盒测试中,这种类型比较容易通过漏洞扫描器直接发现,我们只需要按照扫描结果进行相应的验证就可以了。
相对的在白盒审计中, 我们首先要寻找带参数的输出函数,接下来通过输出内容回溯到输入参数,观察是否过滤即可。
无案例不足以求真,这里我们选用echo()函数
作为实例来分析:
新建 XssReflex.php,代码如下:
1 | <html> |
这是一个很简单、也很常见的页面:
变量 $XssReflex 获取 get 方式传递的变量名为 input 的变量值(值为一个字符串),然后直接通过 echo() 函数输出,注意这中间并未对用户输入进行任何过滤。
打开 Firefox 输入 url:localhost/codeaudit/xss/XssReflex.php
:
当我们输入 1
,页面返回 1 :
当我们输入hello
时,页面返回 hello :
以上都为正常的输出,但如果我们输出一些javascript
代码呢?
比如我们输入<script>alert('xss')</script>
:
可以看到浏览器成功弹窗,说明我们输出的 JavaScript 代码成功被执行了。
我们查看网页 html 代码:
第 12 行增加了:
1 | <script>alert('xss')</script> |
这个弹窗并没有什么实际的意义,但通过它我们知道输入 javascript 代码是可以被执行的,当我们输入一些其他函数,比如document.cookie
就可以成功盗取用户的 cookie 信息,或者读取用户浏览器信息等,为我们进一步深入攻击做铺垫。
3.2 存储型 XSS
和反射性 XSS 的即时响应相比,存储型 XSS 则需要先把利用代码保存在比如数据库或文件中,当 web 程序读取利用代码时再输出在页面上执行利用代码。但存储型 XSS 不用考虑绕过浏览器的过滤问题,屏蔽性也要好很多。
存储型 XSS 攻击流程:
存储型 XSS 的白盒审计同样要寻找未过滤的输入点和未过滤的输出函数。
使用 cat 命令查看 XssStorage.php 代码
1 | shiyanlou:~/ $ cat XssStorage.php |
代码如下:< 参考自JackholeLiu的博客
>
1 | <span style="font-size:18px;"><meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> |
页面功能简述:
这个页面采用 POST 提交数据,生成、读取文本模拟数据库,提交数据之后页面会将数据写入 sql.txt,再打开页面时会读取 sql.txt 中内容并显示在网页上,实现了存储型 xss 攻击模拟。
打开 Firefox 输入 url:localhost/codeaudit/xss/XssStorage.php
:
我们随意输出一些内容:
可以看到页面正常显示页面留言信息。
当我们在 Message 中输入<script>alert('xss')</script>
时,页面成功弹窗 :
并且我们重启浏览器之后再加载该页面,页面依然会弹窗, 这是因为恶意代码已经写入数据库中,每当有人访问该页面时,恶意代码就会被加载执行!
我们查看网页 html 代码:
这就是所谓的存储型 XSS 漏洞,一次提交之后,每当有用户访问这个页面都会受到 XSS 攻击,危害巨大。
3.3 DOM XSS
这种 XSS 用的相对较少,并且由于其特殊性,常见的漏扫工具都无法检测出来,这里先不做讲解。
记个待办,以后来补!
四、XSS 漏洞防范
4.1 反射型 xss 漏洞防范
php 中 xss 的漏洞防范方法总结:<参考自 Segmentfault>
1 | A.PHP直接输出html的,可以采用以下的方法进行过滤: |
这里我们选用 htmlentities() 函数进行测试:
htmlentities() 函数把字符转换为 HTML 实体。
新建 Xss_htmlentities.php, 代码如下:
1 | <html> |
在 Firefox 输入 url:localhost/codoaudit/xss/Xsshtmlentities.php
:
当我们输入<script>alert('xss')</script>
:
可以看到页面并没有弹窗。
我们再查看网页 html 代码:
可以看到 htmlentities() 函数对用户输入的<>
做了转义处理, 恶意代码当然也就没法执行了。
还有其他过滤函数,纸上学来终觉浅,有兴趣的同学可以自己去尝试一番
4.2 存储型 xss 漏洞防范
存储型 XSS 对用户的输入进行过滤的方式和反射型 XSS 相同,这里我们使用htmlspecialchars()
函数进行演示:
htmlentities() : 把预定义的字符 “<” (小于)和 “>” (大于)转换为 HTML 实体
htmlspecialchars 和 htmlentities 的区别:
htmlspecialchars 只转义 & 、" 、' 、< 、>
这几个 html 代码,而 htmlentities 却会转化所有的 html 代码,连同里面的它无法识别的中文字符也会转化。
新建 Xss_htmlspecialchars_Storage.php ,代码如下:
1 | <span style="font-size:18px;"><meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> |
在 Firefox 输入 url:localhost/codoaudit/xss/Xss_htmlspecialchars_Storage.php
:
当我们在 Message 中输入<script>alert('xss')</script>
:
可以看到页面并没有弹窗。
我们再查看网页 html 代码:
可以看到 htmlspecialchars() 函数对用户输入的<>
做了转义处理。