赞
踩
我们不是要做一个能够解决问题的方案,而是要做一个能够 ‘漂亮地’ 解决问题的方案------《白帽子讲web安全》
xss攻击又叫做跨站脚本攻击(cross site script
)* 主要是用户输入或通过其他方式,向我们的代码中注入了一下其他的js,而我们又没有做任何防范,去执行了这段js* 可能破坏者会写一个死循环,将我们的页面给弄崩了; 但是也可以通过这种方式,来获取我们的cookie
,从而获取登陆态等信息,从而造成信息泄露* XSS攻击根据效果可分为反射型、存储型、DOM Based XSS
### 反射型(非持久型XSS攻击)
简单地把用户输入的数据 ‘反射’ 给浏览器,黑客往往需要诱使用户 ‘点击’ 一个恶意链接,才能攻击成功
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>反射型</title>
</head>
<body>
<div id="test"></div>
<script> var $test = document.querySelector('#test');
$test.innerHTML = window.location.hash </script>
</body>
</html>
index.html#<img src="404.html" onerror="alert('xss')" />
* 这时页面一打开就会有个xss的弹窗,这就是最简单的反射型攻击 当然可能会觉得这样没有任何作用,但是修改一下代码```index.html#<img src="404.html" onerror="alert(document.cookie)" />
cookie
* 注意1.必须用IE浏览器打开这个链接,因为 chrome 和 safari 等浏览器,会主动将url里的一下字符串进行encode,保证了一定的安全性。2.为什么我们这里用 img标签 的 onerror 来注入脚本呢?而不是直接用 script 标签来执行,我们修改一下访问的地址 index.html#<script>alert(document.cookie)</script>
,这时会发现,页面并没有执行这段代码,但是这段代码已经注入到了 #test
节点标签中了。所以,一般通过img的onerror来注入是最有效的方法<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>存储型</title> </head> <body> <div id="test"></div> <script> // 先向页面的cookie存储一个name=1的信息 document.cookie = "name=1" // 这里假设是请求了后台的接口 response是我们请求回来的数据 var response = '<img src="404.html" onerror="alert(document.cookie)"' var $test = document.querySelector('#test');; $test.innerHTML = response </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>富文本</title> </head> <body> <div id="test"></div> <textarea name="" id="" cols="30" rows="4"></textarea> <button onclick="submit()">提交</button> </body> </html> <script> function submit() { var $test = document.querySelector('#test'); $test.innerHTML = document.querySelector('textarea').value } </script>
DOM Based XSS
' onclick=alert(/xss/) //
, 页面就能将 <a>标签
中注入攻击代码,点击链接后就会执行。* 或者下面这种情况 ' ><img src=# onerror=alert(/xss2/) />< '
,通过将 <a>标签
闭合,注入 <img>标签
自动执行 onerror 事件,从而达到注入攻击的目的。<script> function inner(){
var str=document.getElementById('InputEle').value;
document.getElementById("LinkEle").innerHTML="<a href='"+str+"'>注入后的链接</a>";
} </script>
<div>
<input type="test" id='InputEle' value=""/>
<input type="button" id="XssEle" value="write" onclick='inner()'/>
<br/>
<a href="" id='LinkEle'>注入后的链接</a>
</div>
encode
也分为 html 的 encode
和 js 的 encode
* html的encode
: 就是将一些有特殊意义的字符串进行替换,比如:& => &" => "' => '< => <> => >
* 通过这些字符的替换,之前我们输入的 <img src="null" onerror="alert()">
就被encode 成了<img src="null" onerror="alert()">
js的encode
: 使用 ‘’ 对特殊字符进行转义,除数字字母之外,小于127的字符编码使用16进制 \xHH
的方式进行编码,大于用 unicode(非常严格模式)* 用 ‘’ 对特殊字符进行转义, 就可以使得js变为一个字符串, 而不是一个可执行的js代码了, 那为什么还需要进行16进制转换和unicode转换呢? 这样做是为了预防一下隐藏字符, 比如换行符可能会对js代码进行换行// 使用“\”对特殊字符进行转义,除数字字母之外,小于127使用16进制“\xHH”的方式进行编码,大于用unicode(非常严格模式)var JavaScriptEncode = function(str){var hex=new Array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');function changeTo16Hex(charCode){return "\\x" + charCode.charCodeAt(0).toString(16);}function encodeCharx(original) {var found = true;var thecharchar = original.charAt(0);var thechar = original.charCodeAt(0);switch(thecharchar) {case '\n': return "\\n"; break; // newlinecase '\r': return "\\r"; break; // Carriage returncase '\'': return "\\'"; break;case '"': return "\\\""; break;case '\&': return "\\&"; break;case '\\': return "\\\\"; break;case '\t': return "\\t"; break;case '\b': return "\\b"; break;case '\f': return "\\f"; break;case '/': return "\\x2F"; break;case '<': return "\\x3C"; break;case '>': return "\\x3E"; break;default:found=false;break;}if(!found){if(thechar > 47 && thechar < 58){ // 数字return original;}if(thechar > 64 && thechar < 91){ // 大写字母return original;}if(thechar > 96 && thechar < 123){ // 小写字母return original;}if(thechar>127) { // 大于127用unicodevar c = thechar;var a4 = c%16;c = Math.floor(c/16); var a3 = c%16;c = Math.floor(c/16);var a2 = c%16;c = Math.floor(c/16);var a1 = c%16;return "\\u"+hex[a1]+hex[a2]+hex[a3]+hex[a4]+"";}else {return changeTo16Hex(original);}}} var preescape = str;var escaped = "";var i=0;for(i=0; i < preescape.length; i++) {escaped = escaped + encodeCharx(preescape.charAt(i));}return escaped;}
### 对于富文本的防范:filter
富文本比较特殊,在富文本中输入标签,我们需要展示出来,所以不能用 html 的 encode 方法来进行防范。所以采用 白名单过滤
的方式来防范。* 原理:列举合法的标签,形成白名单,这些标签是不会对页面进行攻击的。之后对用户输入的内容进行白名单过滤。```
<img src="null" onerror="alert()">
就会被过滤成 <img src="">
这样就有效的防范了用户输入的xss代码* **注意:**1.当遇到需要向后台提交数据的情况,我们应该在用户提交的时候就进行 过滤 和 encode 呢?还是展示的时候处理呢? 我们应当考虑到提交代码后会有个多端展示的问题,可能我们web端需要进行这些处理,但是移动端展示的时候就不需要这些处理,所以我们应当在展示的时候进行处理,而不是录入的时候处理1111
这个信息,其实这个网站悄悄的把这些信息提交到了本地的csrf上了,而不是我们当前浏览的csrf.html中// CSRF.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>csrf</title>
</head>
<body>
<iframe id="" name="csrf-form"></iframe>
<form target="csrf-form" method="post" action="http://127.0.0.1:3001/csrf">
<input name="name" value="1111">
<input type="submit" value="提交">
</form>
</body>
</html>
method=post
判断refererreferer
的报文头,用来指明当前流量的来源参考页。如果我们用post就可以将页面的referer带入,从而进行判断请求的来源是不是安全的网站。但是referer在本地起的服务中是没有的,直接请求页面也不会有。这就是为什么我们要用Post请求方式。直接请求页面,因为post请求是肯定会带入referer,但get有可能不会带referer如果你觉得这篇文章对你有益,烦请点赞以及分享给更多需要的人!
前端实用正则表达式&小技巧,一股脑全丢给你
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。