XSS主要分为反射型、存储型、DOM型。反射型XSS主要是攻击者事先制作好攻击链接, 需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。存储型XSS代码是存储在服务器中的,如在个人信息或发表文章等地方,加入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,每当有用户访问该页面的时候都会触发代码执行。通常用来盗取Cookie,来伪造身份。客户端的脚本程序可以通过DOM动态地检查和修改页面内容,它不依赖于提交数据到服务器端,而从客户端获得DOM中的数据在本地执行,如果DOM中的数据没有经过严格确认,就会产生DOM XSS漏洞。
反射型XSS攻击方法:
无防护测试
1 | <script>alert(1)</script> |
注意有时候输入框会把用户输入的内容返回回来,存放在HTML标签中,这时候要全面仔细地寻找所有可能XSS的地方。
script函数防护
XSS基础防护绕不开的就是htmlspecialchars函数
1 | htmlspecialchars()函数把一些预定义的字符转换为 HTML 实体。 |
注意这里htmlspecialchars是不对单引号做转换的,因此绕过htmlspecialchars就需要考虑能否通过单引号。当处理代码如下时,可以使用单引号
1 | <input name=keyword value='".htmlspecialchars($_GET["XSS"])."'> |
可以通个返回值来判断防护措施。
反射型XSS大体上有两种攻击方式。注入<script>标签和注入标签event属性onclick或者onmouseover
过滤on和<script>关键字
这里插入一个知识点,js伪协议:
1 | <a href="javascript:alert(1)"> |
注意要加上””<>等符号的配对
- 如果使用的是str_replace做限制,可以采用大小写绕过的方法
- javascript伪协议
- 双写绕过,str_replace函数只检查一次
- payload编码绕过,Unicode编码或者HTML实体编码
- 过滤空格时,可以用%2A换行符来替换
一些基础测试语句:
1 | '';!--"<XSS>=&{()} |
存储型XSS
存储型XSS指恶意代码存储在服务端比如mongo或者redis中,服务端读取内容到client端时,如果没有做转义或者过滤,client直接把恶意代码当作HTML标签来解析,从而触发恶意代码执行,主要用于盗取Cookie。payload与反射型大体类似,这里主要讲讲防护方法。
模板渲染时转义
对HTML模板各处插入点进行充分的转义。
常用的模板引擎,ejs、 FreeMarker 、art等,对于HTML转义通常只有一个规则,就是把&<> “ ‘ / 7这几个字符转义掉,能起到一定的XSS防护作用。可以搭建一个demo来看看。

上图为nodejs搭建的一个小型demo,从mongo中读取的username的值是我们写入的恶意payload,注意此时我已经把art-template的escape设置为false,即不对特殊字符转义,直接把这条数据发送到客户端看看效果。

payload执行成功。
当开启escape转义时再看看

很明显看到username的值里面的””做了转义处理,可以看到这里的引号和代码中的引号是不一样的。

前端渲染时也转义作为普通””处理。
值得注意的是,模板引擎的转移规则并不完全,注入内联JavaScript、内联JSON的XSS只用简单的转义并不能很好的防护,如下图

因此还需要在开发时做更为细致的转义处理
开启httpOnly
开启HttpOnly时,可以有效防止恶意代码获取用户cookie,能起到一定效果。对于Http请求走私也有一定的帮助。一般Web框架都默认开启了cookie的httpOnly属性。