浅谈“XSS跨站脚本攻击漏洞”

漏洞名称:

存储型XSS跨站脚本,反射型XSS跨站脚本

描述:

跨站脚本攻击的英文全称是Cross Site Script,为了和样式表区分,缩写为XSS。发生的原因是网站将用户输入的内容输出到页面上,在这个过程中可能有恶意代码被浏览器执行。跨站脚本攻击,它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的。XSS属于被动式的攻击,因为其被动且不好利用,所以许多人常呼略其危害性。而本文主要讲的是利用XSS得到目标服务器的shell。技术虽然是老技术,但是其思路希望对大家有帮助。已知的跨站脚本攻击漏洞有三种:1)存储式;2)反射式;3)基于DOM。

1.存储型跨站脚本攻击涉及的功能点:用户输入的文本信息保存到数据库中,并能够在页面展示的功能点,例如用户留言、发送站内消息、个人信息修改等功能点。

2.反射型跨站脚本攻击涉及的功能点:URL参数需要在页面显示的功能点都可能存在反射型跨站脚本攻击,例如站内搜索、查询功能点。

3.基于DOM跨站脚本攻击涉及的功能点:涉及DOM对象的页面程序,包括(不限这些):

document.URL
document.URLUnencoded
document.location
document.referrer
window.location

检测条件:

1.Web业务运行正常

2.已知待测目标URL,假设为http://www.exmaple.com/page.xxx

3.待测目标存在参数输入,或者以POST方式提交参数,显示为表单方式,假设为name=value。

4.在某种情况下,用户输入被重新显示在网页上,包括名字、帐号、检索结果等等(说明目标网站服务器并没有对用户提交数据检测)。

检测方法:

GET方式跨站脚本:

  1. 在输入的参数后逐条添加以下语句,以第一条为例,输入http://www.exmaple.com/page.xxx?name=<script>alert(123456)</script>只要其中一条弹出显示123456的告警框,就说明存在跨站漏洞,记录漏洞,停止测试。
  2. 如果没有弹出显示123456的告警框,则在返回的页面上单击鼠标右键,选择“查看源文件”。
  3. 查找网页源文件中是否包含完整的字符串<script>alert(123456)</script>,则不管有没有弹出显示123456的告警框,都表明存在跨站脚本漏洞。
  4. 由于有些HTML元素(比如<textarea>或”)会影响脚本的执行,所以不一定能够正确弹出123456告警框,需要根据返回网页源文件的内容,构造value的值,比如
多行文本输入框:

</textarea><script>alert(123456)</script>

文本输入框:

</td><script>alert(123456)</script>  

'><script>alert(123456)</script>

"><script>alert(123456)</script>

</title><script>alert(123456)</script>

--><script>alert(123456)</script>

[img]javascript:alert(123456)[/img]

<scrip<script>t>alert(123456)</scrip</script>t>

</div><Script>alert(123456)</script>

需要对页面上所有可以提交参数的地方进行测试。具体跨站脚本的测试语句根据实际情况的不同而不同,
可自行构造,以及触发事件等切换,这里只列出了一些最常见构造语句。

Post方式跨站脚本:

  1. 在POST表单中逐条输入以下语句,只要其中一条弹出显示123456的对话框,就说明存在跨站漏洞,记录漏洞,停止测试。
  2. <script>alert(123456)</script>
  3. [img]javascript:alert(123456);[/img]
  4. 如果没有弹出显示123456的告警框,则在返回的页面上单击鼠标右键,选择“查看源文件”
  5. 查找网页源文件中是否包含完整的字符串<script>alert(123456)</script>,则不管有没有弹出显示123456的告警框,都表明存在跨站脚本漏洞。
  6. 由于有些HTML元素(比如<textarea>或”)会影响脚本的执行,所以不一定能够正确弹出123456告警框,需要根据返回网页源文件的内容,构造value的值,比如
多行文本输入框:

</textarea><script>alert(123456)</script>

文本输入框:

</td><script>alert(123456)</script>  

'><script>alert(123456)</script>

"><script>alert(123456)</script>

</title><script>alert(123456)</script>

--><script>alert(123456)</script>

[img]javascript:alert(123456)[/img]

<scrip<script>t>alert(123456)</scrip</script>t>

</div><Script>alert(123456)</script>

需要对页面上所有可以提交参数的地方进行测试。具体跨站脚本的测试语句根据实际情况的不同而不同,
可自行构造,以及触发事件等切换,这里只列出了一些最常见构造语句。

 

漏洞修复:

对于XSS跨站漏洞,可以采用以下修复方式:

  1. 总体修复方式:验证所有输入数据,有效检测攻击;对所有输出数据进行适当的编码,以防止任何已成功注入的脚本在浏览器端运行。具体如下 :
  1. 输入验证:某个数据被接受为可被显示或存储之前,使用标准输入验证机制,验证所有输入数据的长度、类型、语法以及业务规则。
  2. 输出编码:数据输出前,确保用户提交的数据已被正确进行entity编码,建议对所有字符进行编码而不仅局限于某个子集。
  3. 明确指定输出的编码方式:不要允许攻击者为你的用户选择编码方式(如ISO 8859-1或 UTF 8)。
  4. 注意黑名单验证方式的局限性:仅仅查找或替换一些字符(如"<" ">"或类似"script"的关键字),很容易被XSS变种攻击绕过验证机制。
  5. 警惕规范化错误:验证输入之前,必须进行解码及规范化以符合应用程序当前的内部表示方法。请确定应用程序对同一输入不做两次解码。对客户端提交的数据进行过滤,一般建议过滤掉双引号(”)、尖括号(<、>)等特殊字符,或者对客户端提交的数据中包含的特殊字符进行实体转换,比如将双引号(”)转换成其实体形式",<对应的实体形式是<,<对应的实体形式是>以下为需过滤的常见字符:
[1] |(竖线符号)
[2] & (& 符号)
[3];(分号)
[4] $(美元符号)
[5] %(百分比符号)
[6] @(at 符号)
[7] '(单引号)
[8] "(引号)
[9] \'(反斜杠转义单引号)
[10] \"(反斜杠转义引号)
[11] <>(尖括号)
[12] ()(括号)
[13] +(加号)
[14] CR(回车符,ASCII 0x0d)
[15] LF(换行,ASCII 0x0a)
[16] ,(逗号)
[17] \(反斜杠)
2、在请求返回页面关键字符进行转义;
[1] “(双引号):&quot
[2] ’ (单引号):&apos
[3] &(&符号):&amp
[4] <(左尖括号):&lt
[5] >(右尖括号):&gt
在不影响应用的前提下,建议将cookie标记为httpOnly,同时禁用TRACE方法。

对于java进行的web业务开发的过滤器如下:

在用java进行web业务开发的时候,对于页面上接收到的参数,除了极少数是不可预知的内容外,大量的参数名和参数值都是不会出现触发Xss漏洞的字符。而通常为了避免Xss漏洞,都是开发人员各自在页面输出和数据入库等地方加上各种各样的encode方法来避免Xss问题。而由于开发人员的水平不一,加上在编写代码的过程中安全意识的差异,可能会粗心漏掉对用户输入内容进行encode处理。针对这种大量参数是不可能出现引起Xss和SQL注入漏洞的业务场景下,因此可以使用一个适用大多数业务场景的通用处理方法,牺牲少量用户体验,来避免Xss漏洞和SQL注入。

利用Servlet的过滤器机制,编写定制的XssFilter,将request请求代理,覆盖getParameter和getHeader方法将参数名和参数值里的指定半角字符,强制替换成全角字符。使得在业务层的处理时不用担心会有异常输入内容。

XssFilter.java

package filter;

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 {

public void init(FilterConfig config) throws ServletException {

}

public void doFilter(ServletRequest request, ServletResponse response,

FilterChain chain) throws IOException, ServletException

{

XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(

(HttpServletRequest) request);

chain.doFilter(xssRequest, response);

}

public void destroy() {

}

XssHttpServletRequestWrapper.java

package filter;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletRequestWrapper;



public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

    HttpServletRequest orgRequest = null;

public XssHttpServletRequestWrapper(HttpServletRequest request) {

    super(request);

    orgRequest = request;

}

/**

* 覆盖getParameter方法,将参数名和参数值都做xss过滤。<br/>

* 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br/>

* getParameterNames,getParameterValues和getParameterMap也可能需要覆盖

*/

@Override

public String getParameter(String name) {

String value = super.getParameter(xssEncode(name));

    if (value != null) {

        value = xssEncode(value);

}

    return value;

}

/**

* 覆盖getHeader方法,将参数名和参数值都做xss过滤。<br/>

* 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br/>

* getHeaderNames 也可能需要覆盖

*/

@Override

public String getHeader(String name) {



String value = super.getHeader(xssEncode(name));

    if (value != null) {

        value = xssEncode(value);

}

      return value;

}

/**

* 将容易引起xss漏洞的半角字符直接替换成全角字符

* @param s

* @return

*/

private static String xssEncode(String s) {

if (s == null || s.isEmpty()) {

return s;

}

StringBuilder sb = new StringBuilder(s.length() + 16);

for (int i = 0; i < s.length(); i++) {

char c = s.charAt(i);

switch (c) {

    case '>':

        sb.append('>');//全角大于号

        break;

    case '<':

        sb.append('<');//全角小于号

        break;

    case '\'':

        sb.append('‘');//全角单引号

        break;

    case '\"':

        sb.append('“');//全角双引号

        break;

    case '&':

        sb.append('&');//全角

        break;

    case '\\':

        sb.append('\');//全角斜线

        break;

    case '#':

        sb.append('#');//全角井号

        break;

    default:

        sb.append(c);
    
        break;

    }

}

    return sb.toString();

}


/**

* 获取最原始的request

* @return

*/

public HttpServletRequest getOrgRequest() {

return orgRequest;

}

/**

* 获取最原始的request的静态方法

* @return

*/

public static HttpServletRequest getOrgRequest(HttpServletRequest req) {

if(req instanceof XssHttpServletRequestWrapper){

return ((XssHttpServletRequestWrapper)req).getOrgRequest();

}


return req;

}

在web.xml中添加

 <filter>

<filter-name>xssFilter</filter-name>

<filter-class>filter.XssFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>xssFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

对于PHP语言所编写的网站系统的XSS过滤器:

<?php  
/**
* @去除XSS(跨站脚本攻击)的函数
* @par $val 字符串参数,可能包含恶意的脚本代码如<script language="javascript">alert("hello world");</script>
* @return  处理后的字符串
* @Recoded By Androidyue
**/
function RemoveXSS($val) {  
   // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed  
   // this prevents some character re-spacing such as <java\0script>  
   // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs  
   $val = preg_replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '', $val);  
 
   // straight replacements, the user should never need these since they're normal characters  
   // this prevents like <IMG SRC=@avascript:alert('XSS')>  
   $search = 'abcdefghijklmnopqrstuvwxyz'; 
   $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';  
   $search .= '1234567890!@#$%^&*()'; 
   $search .= '~`";:?+/={}[]-_|\'\\'; 
   for ($i = 0; $i < strlen($search); $i++) { 
      // ;? matches the ;, which is optional 
      // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars 
 
      // @ @ search for the hex values 
      $val = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ; 
      // @ @ 0{0,7} matches '0' zero to seven times  
      $val = preg_replace('/(&#0{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ; 
   } 
 
   // now the only remaining whitespace attacks are \t, \n, and \r 
   $ra1 = Array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'style', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base'); 
   $ra2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload'); 
   $ra = array_merge($ra1, $ra2); 
   $found = true; // keep replacing as long as the previous round replaced something 
   while ($found == true) { 
      $val_before = $val; 
      for ($i = 0; $i < sizeof($ra); $i++) { 
         $pattern = '/'; 
         for ($j = 0; $j < strlen($ra[$i]); $j++) { 
            if ($j > 0) { 
               $pattern .= '(';  
               $pattern .= '(&#[xX]0{0,8}([9ab]);)'; 
               $pattern .= '|';  
               $pattern .= '|(&#0{0,8}([9|10|13]);)'; 
               $pattern .= ')*'; 
            } 
            $pattern .= $ra[$i][$j]; 
         } 
         $pattern .= '/i';  
         $replacement = substr($ra[$i], 0, 2).'<x>'.substr($ra[$i], 2); // add in <> to nerf the tag  
         $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags  
         if ($val_before == $val) {  
            // no replacements were made, so exit the loop  
            $found = false;  
         }  
      }  
   }  
   return $val;  
}
//测试一下效果
//echo RemoveXSS("<script language='javascript'>alert('hello world');</script>") ;
?>

asp程序网站出现SQL注入 跨站脚本攻击(XSS)漏洞的时候可以使用

源码如下:url=trim(request("url"))
修改如下:url=Server.HTMLEncode(trim(request("url")))
使用Server.HTMLEncode它来解决脚本跨站攻击漏洞
或者:
对用户输入区域只允许适应应用功能所必需的规定字符输入,,对于合法的“>”、“<”“&”这三个符号进行替换:
replace(str,"<","&#x3C;")
replace(str,">","&#x3E;")
replace(str,"&","&#x26;")

 

其他补充:

绕过方法:(待补充)

 

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
跨站脚本攻击(Cross-Site Scripting,XSS)是一种常见的网络安全漏洞,攻击者利用这个漏洞向网站中注入恶意代码,并在用户浏览器上执行。这种攻击通常发生在存在输入输出的网页应用程序中。 XSS攻击主要分为三种类型: 1. 存储型XSS:攻击者将恶意代码存储在目标网站的数据库中,当其他用户访问该网站时,恶意代码被返回并在用户浏览器中执行。 2. 反射型XSS:攻击者构造一个包含恶意代码的URL,并将其发送给目标用户。用户点击链接后,恶意代码从URL中获取并在用户浏览器上执行。 3. DOM-based XSS:攻击者通过修改网页的DOM结构来执行恶意代码,不需要向服务器发送请求。这种类型的XSS攻击主要基于客户端脚本和DOM文档对象模型。 为了防止XSS攻击,开发人员可以采取以下几种措施: 1. 输入验证和过滤:对用户输入的数据进行验证和过滤,确保不允许包含恶意代码。 2. 输出编码:在将数据输出到网页上时,使用适当的编码方式(如HTML实体编码或JavaScript转义)来防止恶意代码的执行。 3. 使用安全的API:避免使用不安全的API,特别是将用户输入作为参数的API。例如,使用textContent替代innerHTML可以防止XSS攻击。 4. 设置HTTP头部:通过设置X-XSS-Protection和Content-Security-Policy头部,可以进一步加强网站的安全性。 请注意,这只是一些常见的防御措施,具体的应对措施还需要根据实际情况和开发框架来确定。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值