您的位置:首页 > 其它

XSS 小结

2016-09-14 17:14 267 查看

前言

上一篇文章中写了关于项目中处理
SQL盲注
的安全漏洞.其中也提到了
XSS
.这篇文章就来说一下XSS 是怎么来进行攻击的,如何对其进行防御.

概述

XSS攻击
:跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为
XSS


XSS
是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。比如这些代码包括HTML代码和客户端脚本。攻击者利用
XSS
漏洞旁路掉访问控制——例如同源策略(same origin policy)。这种类型的漏洞由于被黑客用来编写危害性更大的网络钓鱼(Phishing)攻击而变得广为人知。对于跨站脚本攻击,黑客界共识是:跨站脚本攻击是新型的“缓冲区溢出攻击“,而JavaScript是新型的“ShellCode”。

`XSS`攻击的危害包括:
1、盗取各类用户帐号,如机器登录帐号、用户网银帐号、各类管理员帐号
2、控制企业数据,包括读取、篡改、添加、删除企业敏感数据的能力
3、盗窃企业重要的具有商业价值的资料
4、非法转账
5、强制发送电子邮件
6、网站挂马
7、控制受害者机器向其它网站发起攻击


—-摘自百度百科 XSS攻击

原理

我们首先搭建一个简易的环境来模拟
XSS
攻击 ,其中
xssTest.jsp
代码如下

模拟XSS攻击实例 1

<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
<form action="xssTestServltet" method="get">
<input type="txt" name="userName">
<input type="submit" value="提交">
</form>

<hr>
您输入的账户为: ${userName }

</body>
</html>


后台处理
xssTestServlter.java


@WebServlet("/xssTestServltet")
public class XssTestServltet extends HttpServlet{

@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//接受参数
String userName=request.getParameter("userName");
//存储数据到 作用域
request.setAttribute("userName", userName!=null?userName:"");
//跳转到原页面.
request.getRequestDispatcher("/xssTest.jsp").forward(request, response);
}

}


然后我们请求到测试页面



我们尝试输入 qazxc110,得到的结果为:



此时页面源代码为:



我们注意到,我们的输入的字符被原封不动的显示在 15行的位置.那么我们试想一下,如果我们在输入框中输入 这样一段代码:
<script>alert('xss')</script>
,会是什么样子.按照刚才的测试,那么这次源码中在刚才的位置就应该显示
<script>alert('xss')</script>
这串代码相当于在展示的位置插入了一段javaScript 代码,那么就应该执行alert弹出弹窗 并打印
xss
.

我们按照刚才的假设,在代码中实验.我们输入
<script>alert('xss')</script>
这串代码在文本框中,然后提交页面.然后我得到了一下页面:



这时我们看到浏览器出现了弹窗,说明刚才的那段
script
代码执行了.这个时候也就基本说明了,页面存在
XSS
漏洞了.

此时的页面源码为:



这是一种非常简单的方式.我们只是在页面上弹窗一个字符串而已,显然是执行了
<script></script>
中的代码.那么这里面不但可以写弹窗代码,还可以写其他比如让页面跳转到一个指定的地址.如果这个地址的页面是一个跟当前页面相似的钓鱼页面的话,后果不堪设想.

很多网站都有留言模块.我们可以在留言板上插入一段恶意的代码,提交到后台.由于这段代码是保存在服务器上,若管理员并没有去及时发现并删除这段留言的代码,当范文留言列表的时候,留言会被加载出来.当用户访问这个留言的页面时,这段恶意代码就会执行.实例如下:

模拟XSS攻击实例 2

/**
* 原页面访问地址.
*
*/
@WebServlet("/xssTestServltet")
public class XssTestServltet extends HttpServlet{
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//接受参数
String userName=request.getParameter("userName");
//存储数据到 作用域
request.setAttribute("userName", userName!=null?userName:"");

//模拟存储一个cookie 到 客户端.在xss 攻击链接中获取.
Cookie cookie = new Cookie("xxzx","1234");
response.addCookie(cookie);

//模拟数据库中存储的留言.
request.setAttribute("ly1", "xxzx");
//模拟数据库中存储的留言.这里插入了一段 script 代码.去访问src 对应的xss 攻击 链接.
request.setAttribute("ly2", "<script src='http://localhost:8080/XssTestServlet2'></script>么么哒");
//跳转到原页面.
request.getRequestDispatcher("/xssTest.jsp").forward(request, response);
}
}


/**
* 模拟留言中 xss 攻击的 地址.
*
*/
@WebServlet("/XssTestServlet2")
public class XssTestServlet2 extends HttpServlet{

@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("访问了攻击地址.......");

//得到cookies
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
System.out.println("name:"+cookie.getName());
System.out.println("value:"+cookie.getValue());
}

}
}


这时我们任意用户在浏览器中访问 留言页面时,页面的代码:



留言2
的后面,还去加载了一个 我们之前定义好的
XSS
链接 .这样一来我们除了请求正常的地址,页面还另外请求了攻击的地址:



而在我们XSS 攻击地址的后台.我们获取到了这些信息:



当管理员进入后台来浏览留言时,就会触发,然后管理员的cookie 后后台地址 等等一系列信息都可以被拿到,然后攻击者就可以用一些cookie欺诈工具来更改管理员的cookie ,就可以不用输入账号,密码 也可以以管理员的身份登录进系统.

解决方案

为解决上面出现的问题,现提供两种解决方案.

方案 1

我们使用一个第三方的jar 包.调用第三方的api 来防止 XSS 攻击带来的危险.具体步骤如下:

首先,添加 apache 的commons-lang-2.6.jar .

然后,在后台调用
StringEscapeUtils.escapeHtml(string);
StringEscapeUtils.escapeJavaScript(string);
StringEscapeUtils.escapeSql(string);
对请求过来的参数进行转义,若还需要这些值到前台.我们可以使用;
StringEscapeUtils.unescapeXXX(String)
;(
XXX
可以表示
Html
,
JavaScript
,
Sql
,
Xml
等) 来进行反转义,或者在前台使用js 调用escape 可是可以的.

后台处理action:

@RequestMapping("/stringEscapeUtils")
public void stringEscapeUtils(HttpServletRequest request,HttpServletResponse response){
String  str=request.getParameter("username");
System.out.println("username:   "+str);
System.out.println("escapeSql:   "+StringEscapeUtils.escapeSql(str));
System.out.println("escapeHtml:   "+StringEscapeUtils.escapeHtml(str));
System.out.println("escapeJavaScript:   "+StringEscapeUtils.escapeJavaScript(str));
}


当我们前台输入:
<script>alert('1')</script>
时,后台的输出结果为:



注意:
commons-lang-3.x
里面已经没有
escapeSql
escapeJavaScript
方法,取而代之的是
escapeEcmaScript
.具体的使用方法,就请自行验证了.

方案 2

这里我们重点说一下方案二.这也是我们解决
XSS
攻击时采用的一种方式.

前面我们说到
XSS
攻击无非就是我们对于参数的过滤没有做好.导致一些不安全的字符被原封不动的进入到我们的业务中.那么最终就是对参数进行过滤.在这种方案中.我们需要自己写一个
Filter
,使用
Filter
来过滤发出的请求.对于每个post 的请求的参数过滤一些关键字,把他们替换成安全的.例如:
< > ' " \ / # &
,方法是实现一个自定义的
HttpServletRequestWrapper
,然后在
Filter
里面调用它替换
getParameter
方法即可,具体步骤如下.

首先 我们在后台添加一个
XssHttpServletRequestWrapper
类,让它继承
javax.servlet.http.HttpServletRequestWrapper
,代码如下:

package com.zhouq.filter.Xss;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/** 对请求 的参数 进行 Xss 安全过滤
* @author zhouq
*
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}

/**
* 替换 getParameterValues
*/
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}

int count = values.length;
String[] eccodedValues = new String[count];

// 对每个参数值进行 XSS 清理
for (int i = 0; i < count; i++) {

eccodedValues[i] = cleanXSS(values[i]);
}

return eccodedValues;
}

/**
* 替换 getParameter
*/
public String getParameter(String parameter){
String value=super.getParameter(parameter);
if(value!=null){
//对参数值进行 XSS 清理
value=cleanXSS(value);
}
return value;
}

public String getHeader(String name) {
String value = super.getHeader(name);
if (value == null)
return null;
return cleanXSS(value);
}

/** XSS 清理
* @param value
* @return
*/
private String cleanXSS(String value) {
System.out.println("清理前  :"+value);
value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
value = value.replaceAll("'", "& #39;");
value = value.replaceAll("eval\\((.*)\\)", "");
value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
value = value.replaceAll("script", "");
System.out.println("清理后  :"+value);
System.out.println("----------------------------------------------------------");
return value;
}
}


然后我们还需要在后台添加一个过滤器
XssFilter
,让它实现
javax.servlet.Filter
,具体代码如下:

package com.zhouq.filter.Xss;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class XssFilter implements Filter {

FilterConfig config = null;

@Override
public void destroy() {
this.config = null;
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//执行 我们自己定义的 XssHttpServletRequestWrapper
chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request), response);
}

@Override
public void init(FilterConfig config) throws ServletException {
this.config = config;
}

}


最后,我们还需要在web.xml 中应用 这个过滤器.web.xml 中的配置如下:

<!-- 配置自实现的 XSS 过滤器 -->
<filter>
<filter-name>XssFilter</filter-name>
<filter-class>com.zhouq.filter.Xss.XssFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>XssFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>


到这里.我们的
XSS
清理就编写完成了.每一次请求中的危险字符,敏感信息都会被过滤掉,您可以去测试一下是否对您的应用生效.当然了,如果您要处理更多的字符,那么您可以继续在
cleanXSS
中去添加你需要处理的东西.当然,需要注意的是,一些必要的字符不能被过滤,否则就改变了用户的真实数据.比如在我们当前系统中在为菜单添加操作的时候 会有前缀为
javascript
的代码.那么这里就会被过滤掉.如果你应用中也出现这种情况,那么就得请您自己做取舍了.

假设登录页面有个输入用户名和密码的输入框,可以有很多
XSS
CSRF 注入钓鱼网站
SQL
注入等的攻击手段,例如:

输入用户名 : >"'><script>alert(1779)</script>
输入用户名: usera>"'><img src="javascript:alert(23664)">
输入用户名: "'><IMG SRC="/WF_XSRF.html--end_hig--begin_highlight_tag--hlight_tag--">
输入用户名: usera'"><iframe src="http://demo.testfire.net--en--begin_highlight_tag--d_highlight_tag--">

密码随意输入。


下面提供了一个登录页面的攻击实例,你可以通过下面的方式进行简单的测试:

用户名: `1' or '1'='1`

密码:`<script>alert('xss')</script>`


测试结果:



结束语

到这里,
XSS
攻击的防御措施就写完了,使用
Filter
的这种方式,不仅仅可以防御
XSS
攻击,还可以防御
CSRF
攻击,
SQL注入
等安全问题。

参考资料

freebuf.com XSS系列文章

CSDN WEB安全实战系列文章
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  web应用 xss web安全