前端安全之XSS——可能是全网种类最齐全的XSS

787 阅读3分钟

什么是XSS?

wikipedia中是这样介绍的:
XSS attacks enable attackers to inject client-side scripts into web pages viewed by other users. A cross-site scripting vulnerability may be used by attackers to bypass access controls such as the same-origin policy.

简言之 通过注入客户端脚本(js)呈现给其他用户的攻击手段既XSS
尽管是最常见的安全漏洞,在漏洞统计中依旧占很大比重 (Cross-site scripting carried out on websites accounted for roughly 84% of all security vulnerabilities documented by Symantec up until 2007)

XSS有哪些类型?

  • 反射型(非持久型)

将注入的脚本数据(未存储到数据库)通过服务端反射给其他用户,进行攻击的手段既反射型XSS 反射型XSS.png

  • 存储型(持久型)

存储型和反射型的漏洞数据均由服务端提供,相对于反射型,存储型将漏洞数据存储到了数据库,这就表明只要用户访问了此漏洞数据,便会遭到攻击,所以就危害程度而言: 存储型XSS > 反射型XSS UML时序图-存储型XSS.png

  • DOM Based型

DOM Based 型,表现形式也是反射型,相对于前面两者的本质区别在于,有漏洞的数据并非通过服务端,而是直接由JS执行进行DOM节点的操作所造成的XSS漏洞,如下图案例所示: UML时序图-DOM Based型XSS.png 案例是通过输入框输入,也可能通过url等其他形式注入操作DOM,造成XSS

  • Self XSS

前面提及的XSS都可以通过各种手段影响到其他用户(窃取其他用户cookie、信息等造成危害),Self XSS相对于前文提到的区别在于,漏洞只有在本人当前上下文执行,并不会影响其余用户。 例如个人简介中的nickname存在xss漏洞,即使注入了漏洞脚本,影响范围也仅是本人.

  • Mutated XSS (mXSS)

此类XSS通常是浏览器自行执行一些解析所引起的XSS,看以下例子:

function generateText (inputText) {
  const domElem = document.createElement('div')
  domElem.innerHTML = inputText
  return domElem.innerText
}
看似没什么问题,inputText即使带有普通的html标签,也能正常返回文本,然而却隐藏了安全风险
当执行generateText('\<img onerror="alert(XSS)" src="xx"\>'),alert(XSS)被成功执行了
因为innerHTML自行去解析了HTML,所以导致的XSS漏洞

如何预防?

  • 预防Cookie窃取,设置HttpOnly
  • 对不可信数据进行编码 (涉及XSS注入的场景包括:HTML、Javascript、Base64、HTML Attribute、CSS) XSS攻防示例代码
router.get('/', (ctx, next) => {
  // HTML注入XSS
  const htmlXSS = '<script>alert("HTML XSS")</script>' // ESAPI.encoder().encodeForHTML('<script>alert("XSS")</script>');
  // CSS注入XSS,IE 7 下复现
  const cssXSS=  `expression(alert('CSS XSS'),1)` // ESAPI.encoder().encodeForCSS(`expression(alert('CSS XSS'),1)`)
  // HTML Attribute注入XSS, 漏洞复现访问 http://127.0.0.1:3000/?cb=javascript:alert(123)
  const cbParam = ctx.request.url.slice(ctx.request.url.indexOf('cb') + 3)
  const parsedCb =  cbParam // handleHrefXss(cbParam)
  console.log(cbParam)
  // Javascript 注入XSS
  const jsXSS = `";alert('JS XSS');"`; // ESAPI.encoder().encodeForJavaScript(`";alert('JS XSS');"`)
  // base64 中注入XSS
  const base64XSS = `data:text/html;base64,PHNjcmlwdD5hbGVydCgnYmFzZTY0IFhTUycpPC9zY3JpcHQ+` // ESAPI.encoder().encodeForBase64(`data:text/html;base64,PHNjcmlwdD5hbGVydCgnYmFzZTY0IFhTUycpPC9zY3JpcHQ+`)
  ctx.body = `
    <div>${htmlXSS}</div>
    <a href=${parsedCb}>HTML Attribute XSS</a>
    <div style="height:${cssXSS}"></div>
    <h2>Base64 XSS: </h2>
    <iframe src=${base64XSS}>Base64 XSS</iframe>
    <script>
      var a = "${jsXSS}"
    </script>
  `;
});

  • 响应头添加CSP策略
  • 未支持CSP旧版浏览器,添加X-XSS-Protection

参考文献