web安全防范之XSS漏洞攻击


  本文标签:XSS web安全

近期在cnode社区,由@吴中骅的一篇关于XSS的文章,直接招致了社区的人开始在cnode尝试各种 突击  。这里总结了一下这次碰到的一些问题与解决 方案  。

文件上传 漏洞

之前nodeclub在上传图片的时候逻辑是这样的:

  1. //消费者上传的文件名  
  2. var filename = Date.now() + _ + file.name;  
  3. //消费者文件夹  
  4. var userDir = path.join(config.upload_dir, uid);  
  5. //最后文件 保留的路径  
  6. var savepath = path.join(userDir, filename);  
  7. //将消费者上传的文件从暂时目录移动到最后 保留路径  
  8. fs.rename(file.path, savepath, callback);  
  9.  

看上去 如同没有问题,每个人上传的文件都 存放在以消费者UID命名的一个文件夹内,而且以目前的 工夫戳作前缀  。然而当有消费者 歹意 构造输入的时候,问题就浮现了  。当消费者上传的文件filename为/../../xxx的时候,上传的文件就会rename到消费者文件夹之外,招致消费者 可以替换现有系统上的任何文件  。

这个 漏洞 绝对来说十分的低级,然而 后果却是最严峻的,直接招致整个系统都可能被消费者操纵  。修复的 步骤也很 方便:

  1. var filename = Date.now() + _ + file.name;  
  2.  
  3. var userDir = path.join(config.upload_dir, uid);  
  4.  
  5. //猎取最后 保留到的绝对路径  
  6. var savepath = path.resolve(path.join(userDir, filename));  
  7. //验证  
  8. if (savepath.indexOf(path.resolve(userDir)) !== 0) {  
  9. return res.send({status: forbidden});  
  10. }  
  11. fs.rename(file.path, savepath, callback);  
  12.  

富文本编辑器的XSS

关于XSS,在@吴中骅的文章中已经十分 详尽的 形容了  。而cnode社区中,消费者发表话题和回复话题也是用的一个 支撑markdown 格局的富文本编辑器  。之前是没有做过任何XSS 提防措施的,于是...你 可以直接在里面写:

  1. <script>alert(123);script> 
  2. <div onmouseover="alert(123)">div> 
  3. <a href="javascript:alert(123);">123a> 
  4.  

而markdown 格局的内容也没有做URL有效性检测,于是各种 款式的XSS又出来了:

[xss][1]

[xss][2]

![xss][3]

[1]: javascript:alert(123);

[2]: http://www.baidu.com/#"onclick=alert(123)

[3]: http://www.baidu.com/img.jpg#"onmouseover=alert(123)

在社区这个 利用场景下,引入HTML标签只不过为了进行一些排版的操作,而 其余的 款式定义等等都只会让整个界面一团糟,更别说还有潜在的XSS 漏洞风险  。 因此,其实我们是不需求 支撑消费者输入HTML标签来进行内容排版的, 所有都 可以通过markdown来 接替  。 而后通过 方便 粗野的HTML escape,就 可以泯灭掉直接输入HTML招致的XSS风险  。

  1. function escape(html) {  
  2. return html.replace(/&(?!\w+;)/g, &)  
  3. .replace(/g, <)  
  4. .replace(/>/g, >)  
  5. .replace(/"/g, ");  
  6. } 

然而这样 粗野的进行escape,会招致消费者输入的代码里面的< > ;这些特别字符也被转义掉,不能正确显示,需求先将代码段提 存入来 保留,只转义非代码段的 部分  。于是这个escape函数变成了这样:

  1. function escape(html) {  
  2. var codeSpan = /(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm;  
  3. var codeBlock = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?='0))/g;  
  4. var spans = [];  
  5. var blocks = [];  
  6. var text = String(html).replace(/\r\n/g, \n)  
  7. .replace(/\r/g, \n);  
  8. text = \n\n + text + \n\n;  
  9. texttext = text.replace(codeSpan, function(code) {  
  10. spans.push(code);  
  11. return `span`;  
  12. });  
  13. text += '0;  
  14. return text.replace(codeBlock, function (whole, code, nextChar) {  
  15. blocks.push(code);  
  16. return \n\tblock + nextChar;  
  17. })  
  18. .replace(/&(?!\w+;)/g, &)  
  19. .replace(/g, <)  
  20. .replace(/>/g, >)  
  21. .replace(/"/g, ")  
  22. .replace(/`span`/g, function() {  
  23. return spans.shift();  
  24. })  
  25. .replace(/\n\tblock/g, function() {  
  26. return blocks.shift();  
  27. })  
  28. .replace(/'0$/,)  
  29. .replace(/^\n\n/, )  
  30. .replace(/\n\n$/, );  
  31. };  
  32.  

而关于markdown生成的标签和标签中的href属性,必须要做URL有效性检测或者做xss的过滤  。这样 保障通过markdown生成的HTML代码也是没有XSS 漏洞的  。

由于XSS的 目的 确切 比较多,见XSS Filter Evasion Cheat Sheet  。 因此 可以做 粗野的HTML escape是最安全的,然而并不是每一个地方都 可以通过markdown来 接替HTML代码,所以不是每一个地方都能用HTML escape,这个时候就需求 其余的 目的来过滤XSS 漏洞了  。

XSS 提防不得不通过定义白名单的 模式,例如只同意

标签,只同意href class style属性  。 而后对每一个可能造成XSS的属性进行特定的过滤  。

现有的XSS过滤模块,一个是node-validator, 一个是@雷宗民写的js-xss  。

不 可以 保障XSS模块 可以 提防住任意的XSS 突击,然而起码 可以过滤掉大 部分 可以 设想到的 漏洞  。node-validator的XSS() 依旧有bug,关于

  • <img src=<%= reply.author.avatar_url %> title=<%= reply.author.name %> /> 
  • <img src="<%= reply.author.avatar_url %>" title="<%= reply.author.name %>" /> 
  • 上面两条语句,第一句由于 使用的是单引号,消费者 可以通过 构造一个avatar_url中带单引号,来截断src属性,后面就 可以 随便加javascript代码了  。

    CSRF 突击

    CSRF 突击在node的web开发框架connect和express等中都有了解决方 方案  。通过在访客的session中 存放一个随机的_csrf字段,模版引擎在生成HTML文件的时候将这个_csrf值传递到前端,访客提交的任意POST 申请,都必须带上这个字段进行验证, 保障了惟独目前消费者在目前页面上 可以进行 批改的操作  。

    然而当页面存在XSS 漏洞的时候,CSRF的这种 提防措施就成了浮云  。 歹意 突击者 彻底 可以通过javascript代码,猎取到 其余消费者的_csrf值,并直接 模仿消费者的POST 申请进行服务端数据的更改  。