XSS(Cross-site scripting),跨站脚本攻击。将渲染到前端的字符串巧妙地处理成可执行的 JavaScript 代码的攻击手段。大体可以分为以下两种方式
- 反射型
- 存储型
XSS 的危害
- 窃取 Cookies,JavaScript 能直接获取到当前域的 Cookies,同时发送请求并携带 Cookies 到黑客的服务器
- 篡改页面内容
- 弹出广告
- 流量劫持和恶意跳转
- 等等
反射型
反射型,一般是在 URL 地址栏做文章,比如某个 url 为 localhost:8080/error?msg=错误信息
,后端拿到 msg 后进行模板渲染
<p><?php echo $msg; ?><p>
这时候如果将url修改为 localhost:8080/error?msg=<script>alert('hello world')</script>
,渲染到前端的内容就变为
<p><script>alert('Hello World');</script></p>
这就成为了一个 XSS 注入点
存储型
存储型,指的是注入代码被保存进数据库或其他存储容器中,下次用户访问到特定页面的时候,触发了执行代码。相比于反射型,存储型的危害性更大,更不容易被用户察觉
通过 HTML 标签注入 XSS
<?php
$content = <<<XSS
<script>alert('Hello World');</script>
XSS;
?>
<p><?php echo $content; ?></p>
执行后结果为
<p><script>alert('Hello World');</script></p>
通过 HTML 属性注入 XSS
<?php
$url = <<<XSS
/aaa.png" onerror="alert('Hello World')
XSS;
?>
<img src="<?php echo $url; ?>">
执行后结果为
<img src="/aaa.png" onerror="alert('Hello World')">
因为 /aaa.png
这张图片是不存在的,所以会执行 onerror
。可以用来注入的 XSS 的 HTML 标签属性还有
onclick
onload
onmousemove
- 等等
通过 JavaScript 代码注入
<?php
$name = <<<XSS
";alert("Hello World");"
XSS;
?>
<script>
var name = "<?php echo $name; ?>";
</script>
执行后结果为
<script>
var name = "";alert("Hello World");"";
</script>
通过 CSS 样式注入
CSS 样式也是能被注入的,比如 background
等,所以在动态操作 CSS 样式的时候也需要格外小心
利用编码注入
首先我们讲下浏览器解析 HTML 文档的过程。当浏览器接收到 HTML 文档时,会触发 HTML 解析器对 HTML 文档进行词法分析,同时进行 HTML 解码和生成 DOM 树。接下来 JavaScript 解析器会介入对内联脚本进行解析,这一过程会完成 JavaScript 的解码工作。如果浏览器遇到 URL 时,这时候 URL 解析器也会对 URL 进行解码,URL 解析器的解码顺序会根据 URL 所在位置不同,可能在 JavaScript 解码之前或之后
HTML 编码
早期 HTML 文档是通过 ASCII 编码进行传输的,后来,从 HTML2.0 到 HTML4.01,ISO-8859-1 字符集被认定为标准。然而上述的编码字符集是有限的,在多语言环境中是不兼容的,所以 Unicode 联盟开发了 Unicode 标准。现在 HTML5 默认采用的编码为 UTF-8
在 HTML 页面中可以采用 &#+十进制编码+;
来表示对应的字符,如 A
表示字符 A
URL 编码
早期 URL 只能使用 0-9a-zA-Z
和 $-\_.!\*'(),"
,这是 RFC 1738 规定的。然而由于没有硬性规定使用何种编码,所以导致各家浏览器都不太一样,不过现如今浏览器一般默认使用和页面一样的编码,现在 HTML5 页面默认采用 UTF-8 编码,所以 URL 编码默认也为 UTF-8
在 URL 地址中可以采用 %+十六进制编码
来表示对应的字节,如汉
对应的 UTF-8 编码的十六进制为 E4B8AD
,所以 URL 编码每个字节后的结果为 %E4%D8%AD
JavaScript 编码
JavaScript 编码采用的是 Unicode 编码,比如汉
对应的 Unicode 编码的十六进制为 4E2D
,所以它编码后可以表示为 \u4E2D
例子
<?php
// 原文
$url1 = "javascript:alert('Hello World');";
// 1. JavaScript 编码后
$url2 = "javascript:\\u0061\\u006c\\u0065\\u0072\\u0074('Hello World');";
// 2. URL 编码
$url3 = "javascript:%5cu0061%5cu006c%5cu0065%5cu0072%5cu0074('Hello World')";
// 3. HTML 编码
$url4 = "javascript:%5cu0061%5cu006c%5cu0065%5cu0072%5cu0074('Hello World')";
?>
<a href="<?php echo $url1; ?>">url1</a>
<a href="<?php echo $url2; ?>">url2</a>
<a href="<?php echo $url3; ?>">url3</a>
<a href="<?php echo $url4; ?>">url4</a>
点击页面中的四个按钮,你会发现都能弹出 alert 框
富文本-白名单过滤
富文本编辑器是非常容易被 XSS 的点,因为我们根本没办法对数据进行转义处理。常见的手段是使用标签白名单,只保留合法的 HTML 标签和属性。常见的库有
在做白名单处理时,应选择对非法的标签和属性做转义处理,而不是干掉标签或属性,防止当干掉标签或属性后,正好形成了新的注入点
<scr<script>alert(1);</script>ipt>alert(1);</scr<script>alert(1);</script><ript>
干掉非法标签 script
<script>alert(1);</script>
正好形成了新的注入点
防范手段
- CSP,最有效的防范手段
- 后端对接收的字段做数据类型判断和类型转换
- 富文本-白名单过滤
- 开启 HttpOnly,禁止 JavaScript 操作 Cookies
- 转义引号和尖括号(
<
和>
) - 转义特殊字符
#
,%
,\
,防止编码注入
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。