一个反射型XSS例子的解析

一个反射型XSS例子的解析我们在访问一个网页的时候,在URL后面加上参数,服务器根据请求的参数值构造不同的HTML返回。如http://localhost:8080/prjWebSec/xss/reflectedXSS.jsp?param=value…上例中的value可能出现在返回的HTML(可能是JS,HTML某元素的内容或者属性)中,如果将value改成可以在浏览器中被解释执行的东西,就形成了反射型X

大家好,又见面了,我是你们的朋友全栈君。我们在访问一个网页的时候,在URL后面加上参数,服务器根据请求的参数值构造不同的HTML返回。

如http://localhost:8080/prjWebSec/xss/reflectedXSS.jsp?param=value…

上例中的value可能出现在返回的HTML(可能是JS,HTML某元素的内容或者属性)中,

如果将value改成可以在浏览器中被解释执行的东西,就形成了反射型XSS.

有人会问,我怎么可能自己去把value改成可以执行的恶意代码呢?这不是自己坑自己吗.

但是一种情况是别人可能修改这个value值,然后将这个恶意的URL发送给你,或者别人,当URL地址被打开时,

特有的恶意代码参数被HTML解析,执行.它的特点是非持久化,必须用户点击带有特定参数的链接才能引起.

下面来看一个简单的例子:

utilits.js:
	function writeToDom(str){
		document.writeln(str);
	}
	function writelnToDom(str){
		document.writeln(str + "<br>");
	}
reflectedXSS.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="org.apache.commons.lang.StringEscapeUtils"%>
<%@ page import="java.net.URLDecoder,java.net.URLEncoder"%>
<%@ page import="org.owasp.esapi.ESAPI"%>
<!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>test XSS</title>
<script type="text/javascript" src="../js/utilits.js"></script>
</head>
<%
	String param = request.getParameter("param");
	System.out.println("original " + param);
%>
<script>
	var scriptVar='<%=param%>';
	writelnToDom("original: " + scriptVar);	
</script>
<body>
</body>
</html>

当用户通过URL http://localhost:8080/prjWebSec/xss/reflectedXSS.jsp?param=value访问的时候,

浏览器输出original: value

但是如果URL改成 http://localhost:8080/prjWebSec/xss/reflectedXSS.jsp?param=value’;alert(‘x’)//

浏览器会先alert,然后输出original: value.

查看浏览器的源码可以看到:var scriptVar=’value’;alert(‘x’)//’;

当value’;alert(‘x’)//被返回给浏览器的时候var scriptVar='<%=param%>’;变成了

var scriptVar=’value’;alert(‘x’)//’;

这就是一个简单的反射型XSS实例.

下面我们来看怎么防止这种XSS.commons-lang和OWASP的ESAPI都提供了工具类。

<%
	String param = request.getParameter("param");
	System.out.println("original " + param);
	String secparam = StringEscapeUtils.escapeJavaScript(request.getParameter("param"));
	System.out.println("StringEscapeUtils " + secparam);
	String owaspparam = ESAPI.encoder().encodeForJavaScript(request.getParameter("param")); 
	System.out.println("OWASP " + owaspparam);
	
	out.write("server side output -------------------------------------------------------  ");
	out.write("<br>original: " + param);
	out.write("<br>StringEscapeUtils: " + secparam);
	out.write("<br>OWASP: " + owaspparam);
%>
<script>
	writelnToDom("<br> client side output---------------------------------------------");
	var scriptVar='<%=param%>';
	writelnToDom("original: " + scriptVar);
	var secVar='<%=secparam%>';
	writelnToDom('StringEscapeUtils:' + secVar);
	
	var owaspparam='<%=owaspparam%>';
	writelnToDom("OWASP: " + owaspparam);
</script>

以这个URL来测试

http://localhost:8080/prjWebSec/xss/reflectedXSS.jsp?param=value中文’;alert(‘x’)//<>

system.out的输出为:
original value中文';alert('x')//<>
StringEscapeUtils value\u4E2D\u6587\';alert(\'x\')//<>
OWASP value\u4E2D\u6587\x27\x3Balert\x28\x27x\x27\x29\x2F\x2F\x3C\x3E

浏览器会alert一次,同时输出下面的内容

server side output -------------------------------------------------------
original: value中文';alert('x')//<>
StringEscapeUtils: value\u4E2D\u6587\';alert(\'x\')//<>
OWASP: value\u4E2D\u6587\x27\x3Balert\x28\x27x\x27\x29\x2F\x2F\x3C\x3E
client side output---------------------------------------------
original: value中文
StringEscapeUtils:value中文';alert('x')//<>
OWASP: value中文';alert('x')//<>

StringEscapeUtils.escapeJavaScript会对单引号’和双引号”前面加上转意符(\),对宽字节字符

进行unicode编码(\u+十六进制).

ESAPI.encoder().encodeForJavaScript会对所有非数字和非英文字符的字符进行编码,对宽字节字符

进行unicode编码,对其他字符进行\x+十六进制编码。

浏览器执行JavaScript的时候会解释转意和解码成字符.相当于自动调用了JavaScripte的unescape方法.

通过escapeJavaScript和encodeForJavaScript可以避免输出到JavaScript的内容被当做JavaScript执行。

那下面这个URL会发生什么事情呢?    

http://localhost:8080/prjWebSec/xss/reflectedXSS.jsp?param=1中文’;alert(‘x’)//<img src=@ onError=”javascript:alert(‘error’)”>

会弹出一个alert(‘x’)和3次alert(‘error’),同时DOM里被添加了3个

<img οnerrοr=”javascript:alert(‘error’)” src=”@”>

这是什么原因造成的呢?alert(‘x’)的执行还是因为没有对Javascript的元素进行编码.

另外3个alert(‘error’)是因为html内容没有经过html编码,在DOM里插入了3个img元素,取不到src指定的

图片,从而触发了onerror事件.

解决的方法是如果要将返回数据做为HTML节点的内容,一定要保证内容被真正的当做数据来解释,

而不要被解释成html元素。

StringEscapeUtils.escapeHtml和ESAPI.encoder().encodeForHTML可以帮助我们完成这个功能.

下面的代码既保证了不被当做Javascript脚本,也保证了不被解释成HTML元素.

<%
String doubleSecparam = StringEscapeUtils.escapeJavaScript(
StringEscapeUtils.escapeHtml(request.getParameter("param")));

String doubleOwasp = ESAPI.encoder().encodeForJavaScript(
ESAPI.encoder().encodeForHTML(request.getParameter("param")));
%>
<script>
	var doubleScriptVar='<%=doubleSecparam%>';
	writelnToDom("doubleSecparam StringEscapeUtils: " + doubleScriptVar);
	var doubleOwasp='<%=doubleOwasp%>';
	writelnToDom("Double OWASP: " + doubleOwasp);	
</script>

查看浏览器的源码,我们发现html元素会被编码成html entity

var doubleScriptVar='1中文\';alert(\'x\')//<img 
src=@ onError="javascript:alert(\'error\')">';

var doubleOwasp='1\x26\x23x4e2d\x3B\x26\x23x6587\x3B\x26\x23x27\x3B\x26\x23x3b\x3Balert\x26
\x23x28\x3B\x26\x23x27\x3Bx\x26\x23x27\x3B\x26\x23x29\x3B\x26\x23x2f\x3B\x26\x23x2f\x3B
\x26lt\x3Bimg\x20src\x26\x23x3d\x3B\x26\x23x40\x3B\x20onError\x26\x23x3d\x3B
\x26quot\x3Bjavascript\x26\x23x3a\x3Balert\x26\x23x28\x3B\x26\x23x27\x3Berror
\x26\x23x27\x3B\x26\x23x29\x3B\x26quot\x3B\x26gt\x3B';

当然,现实过程中,很少有网站有如此明显的xss漏洞.这里只是给大家示范了一下反射型xss的原理,现实中的漏洞虽然五花八门,但是本质是不变的.

两个有用的链接

http://blog.csdn.net/langyan666/article/details/5524479

http://lcamtuf.coredump.cx/

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/137828.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Python.win32gui.获取窗体「建议收藏」

    Python.win32gui.获取窗体「建议收藏」importwin32gui,win32conimportpyautoguiaspg#自己的库fromastd.lib.astd_funcimportfind_pic#窗体标题,用spy++获取wdname=’傲视天地-1-5合区-360游戏中心-MozillaFirefox’#None表示从最顶层桌面找起,如果未找到返回0#从顶层窗口向下搜索主窗…

    2022年10月29日
  • linux平均负载什么意思_负荷率和负载率一样吗

    linux平均负载什么意思_负荷率和负载率一样吗1,Linux系统的平均负载是什么?特定时间间隔内运行队列中的平均进程数,好象还不够明白:就是进程队列的长度,有多少个进程在排队等待运行2,什么是”进程队列”?一个进程满足以下条件就会位于进程队列中1,它没有在等待I/O操作的结果2,它没有主动进入等待状态(即没有调用wait)3,它没有被停止3,如何查看平均负载?最简单的命令是uptime例子:[www.linuxidc.com@localho…

  • 邮件服务器配置「建议收藏」

    邮件服务器postfix仅提供smtp服务,不提供pop3和imap服务,主要是用发送和接收邮件的(接收到的邮件后,一般转交dovecot处理,dovecot负责将postfix转发过来的邮件保存到服务器硬盘上)dovecot仅提供pop3和imap服务,不提供smtp服务(Foxmail之类的邮箱客户端,都是通过pop3和imap来收发邮件的。…

  • ipv6的ping_ping详解

    ipv6的ping_ping详解背景为什么需要使用IPv6,一个最直接的答案就是目前广泛应用的IPv4已经无法提供足够的IP地址来满足迅速增长的网络。IPv4采用32位地址长度,只有大约43亿个地址,很快就将被分配完毕。而IPv6采用128位的地址长度,几乎可以不受限制的提供地址。当然扩大地址空间只是IPv6的众多优势中的重要一项,除此之外,IPv6还能够提高网络的整体吞吐量、改善服务质量(QoS)、安全性有更好的保证、支持即插即用和移动性、更好实现多播功能等等。IPv6的地址获取方式与IPv4有所

    2022年10月30日
  • aliddns ipv6_利用阿里云ddns动态解析ipv6地址[通俗易懂]

    aliddns ipv6_利用阿里云ddns动态解析ipv6地址[通俗易懂]目前家庭宽带基本都可以通过设置连上ipv6网络,有了ipv6之后,每台设备就都有了自己独有的ip地址,这样我们就可以通过外网利用ipv6地址直接访问家里的设备,让家里的设备实现服务器的效果。但是目前设备分配到的ipv6的地址是变化的,所以你就需要通过一些手段把变化的ipv6地址绑定到不变的域名上,这样就可以直接用域名访问家里的设备了。下面就探讨一下利用阿里云ddns动态解析ipv6地址的方法。一、…

  • Redis如何启动_电脑一直卡在配置更新100%

    Redis如何启动_电脑一直卡在配置更新100%Redis的配置、启动、操作和关闭一.启动Redis1.默认配置启动执行redis-server命令,按照默认的redis.conf配置文件中的配置启动Redis,如下:因为默认配置无法自定义配置。所以该方式不会再生产环境中使用2.运行配置启动在命令redis-server后加上要修改的配置名和值(可以设置多对),没有设置的………

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号