作为安全方面的小白,笔记当然要从基础开始,简单的来
先说说XSS即跨站脚本攻击
- 跨站脚本攻击的原理
XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意脚本代码,而程序对于用户输入内容未过滤,当用户浏览该页之时,嵌入其中Web里面的脚本代码会被执行,从而达到恶意攻击用户的特殊目的。
跨站脚本攻击的危害:窃取cookie、放蠕虫、网站钓鱼 ...
跨站脚本攻击的分类主要有:存储型XSS、反射型XSS、DOM型XSS
XSS漏洞是Web应用程序中最常见的漏洞之一。如果您的站点没有预防XSS漏洞的固定方法,那么就存在XSS漏洞。这个利用XSS漏洞的病毒之所以具有重要意义是因为,通常难以看到XSS漏洞的威胁,而该病毒则将其发挥得淋漓尽致。
理论知识久说到这里,后面链接有详情的描述,不懂得可以去看或者百度
https://www.cnblogs.com/caijh/p/6163334.html 这个地方对XSS是怎样进行攻击的进行了具体的解说
下面我们来看看怎么防御XSS攻击:
a:HttpOnly 浏览器禁止页面的JS访问带有HttpOnly属性的Cookie。
b:输入检查 XSS Filter 对输入内容做格式检查,类似“白名单”,可以让一些基于特殊字符的攻击失效。在客户端JS和服务器端代码中实现相同的输入检查(服务器端必须有)。
c:输出检查 在变量输出到html页面时,可以使用编码或转义的方式来防御XSS攻击 HtmlEncode:将字符转成HTMLEntities,对应的标准是ISO-8859-1。
JS中可以使用JavascriptEncode。需要对“\”对特殊字符转义,输出的变量的必须在引号内部。
d:XSS的本质是“HTML注入”,用户的数据被当成了HTML代码一部分来执行,从而混淆了原本的语义,产生了新的语义。
在Html标签中输出:<div>var"></div> 攻击方法:<div id="abc" name=""><script>alert(/XSS/)</script><""></div>
防御方法:采用HtmlEncode。 在OWASP ESAPI中推荐了一种更严格的HtmlEncode:除了字母、数字外,所有的特殊字符都被编码成HTMLEntities。
在<script>标签中输出:<script>var x = "";alert(/XSS/);//";<script>
防御方法:使用JavascriptEncode。
在事件中输出:与在<script>标签中输出类似:<a href=# onclick="funcA('');alert(/XSS/);//')">test</a>
防御方法:使用JavascriptEncode。
在CSS中输出:方式多样
防御方法:尽可能禁止用户可控制的变量在"<style>标签"、"html标签的style属性"、"CSS文件"中输出。如果一定有此需求,则推荐使用 OWASP ESAPI 中的encodeForCSS()函数。除了字母、数字外的所有字符都被编码成十六进制形式“\uHH”。
在地址中输出:比较复杂。一般是在URL的path(路径)或者search(参数)中输出,使用URLEncode即可。
<a href="http://www.evil.com/?test=$var">test</a> --> <a href="http://www.evil.com/?test=" onclick=alert(1)"" >test</a>
整个URL都被用户完全控制时,URL的Protocal(http://) 和Host (www.evil.com)部分不能使用URLEncode,可能会构造伪协议实施攻击:
<a href="$var"></a> --> <a href="javascript:alert(1);"></a>
防御方法:先检查变量是否以”http“开头(如果不是则自动添加),以保证不会出现伪协议类的XSS攻击。在此之后,再对变量进行URLEncode。
e:处理富文本 网站允许用户提交一些自定义的HTML代码,称之为”富文本“。比如用户在论坛里发帖,帖子的内容有图片、视频、表格等,这些”富文本“的效果都需要通过HTML代码来实现。
防御方法:与输入检查的思路一致。使用"XSS Filter":“事件”应该被严格禁止;一些危险的标签:<iframe>、<script>、<base>、<form>等也应严格禁止;在标签、属性、事件的选择上,应该使用白名单,避免使用黑名单。比如,只允许<a>、<img>、<div>等比较“安全”的标签存在。可使用一些开源项目:Anti-Samy 是OWASP上的一个开源项目,可使用于Java、.NET等。 HTMLPurify可使用于PHP中。
f:防御DOM Based XSS 如果是输出到事件或脚本,要做一次javascriptEncode;如果是输出到HTML内容或者属性,要做一次HtmlEncode。
这个参考:https://www.cnblogs.com/443855539-wind/p/6055816.html
上面的防御方法中说到了使用HtmlEncode和JavascriptEncode,下面我们来说说实现
JavaScriptEncode
使用“\”对特殊字符进行转义,除数字字母之外,小于127的字符编码使用16进制“\xHH”的方式进行编码,大于用unicode(非常严格模式)。
//使用“\”对特殊字符进行转义,除数字字母之外,小于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; //newline
case '\r': return "\\r"; break; //Carriage return
case '\'': 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用unicode
var 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;
}
HtmlEncode
将字符转换成HTMLEntites,以对抗XSS,这个方法要意义啊去匹配,感觉有点麻烦,但是好在容易理解
var HtmlEncode = function(str){
var hex = new Array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');
var preescape = str;
var escaped = "";
for(var i = 0; i < preescape.length; i++){
var p = preescape.charAt(i);
escaped = escaped + escapeCharx(p);
}
return escaped;
function escapeCharx(original){
var found=true;
var thechar=original.charCodeAt(0);
switch(thechar) {
case 10: return "<br/>"; break; //newline
case 32: return " "; break; //space
case 34:return """; break; //"
case 38:return "&"; break; //&
case 39:return "'"; break; //'
case 47:return "/"; break; // /
case 60:return "<"; break; //<
case 62:return ">"; break; //>
case 198:return "Æ"; break;
case 193:return "Á"; break;
case 194:return "Â"; break;
case 192:return "À"; break;
case 197:return "Å"; break;
case 195:return "Ã"; break;
case 196:return "Ä"; break;
case 199:return "Ç"; break;
case 208:return "Ð"; break;
case 201:return "É"; break;
case 202:return "Ê"; break;
case 200:return "È"; break;
case 203:return "Ë"; break;
case 205:return "Í"; break;
case 206:return "Î"; break;
case 204:return "Ì"; break;
case 207:return "Ï"; break;
case 209:return "Ñ"; break;
case 211:return "Ó"; break;
case 212:return "Ô"; break;
case 210:return "Ò"; break;
case 216:return "Ø"; break;
case 213:return "Õ"; break;
case 214:return "Ö"; break;
case 222:return "Þ"; break;
case 218:return "Ú"; break;
case 219:return "Û"; break;
case 217:return "Ù"; break;
case 220:return "Ü"; break;
case 221:return "Ý"; break;
case 225:return "á"; break;
case 226:return "â"; break;
case 230:return "æ"; break;
case 224:return "à"; break;
case 229:return "å"; break;
case 227:return "ã"; break;
case 228:return "ä"; break;
case 231:return "ç"; break;
case 233:return "é"; break;
case 234:return "ê"; break;
case 232:return "è"; break;
case 240:return "ð"; break;
case 235:return "ë"; break;
case 237:return "í"; break;
case 238:return "î"; break;
case 236:return "ì"; break;
case 239:return "ï"; break;
case 241:return "ñ"; break;
case 243:return "ó"; break;
case 244:return "ô"; break;
case 242:return "ò"; break;
case 248:return "ø"; break;
case 245:return "õ"; break;
case 246:return "ö"; break;
case 223:return "ß"; break;
case 254:return "þ"; break;
case 250:return "ú"; break;
case 251:return "û"; break;
case 249:return "ù"; break;
case 252:return "ü"; break;
case 253:return "ý"; break;
case 255:return "ÿ"; break;
case 162:return "¢"; break;
case '\r': break;
default:
found=false;
break;
}
if(!found){
if(thechar>127) {
var 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 "&#x"+hex[a1]+hex[a2]+hex[a3]+hex[a4]+";";
}
else{
return original;
}
}
}
}
这里给一个测试案例看看
<button onclick='alert("1\x29\x3balert\x282\u54c8\u54c8\x29")'>测试JavaScriptEncode值</button>
<div><script>alert('1哈哈' /);</script></div>
不是我想吐槽,我想说要是真心都这样写,先不说写的人如何,对接手的人来说就是噩梦
接着来提供另外的方法:在表单提交或者url参数传递前,对需要的参数进行过滤
这个就留给大家来填充吧,我要搬砖去了