XSS 攻击是页面被注入了恶意的代码

常见攻击

  1. 在 HTML 中内嵌的文本中,恶意内容以 script 标签形成注入。
  2. 在内联的 JavaScript 中,拼接的数据突破了原本的限制(字符串,变量,方法名等)。
  3. 在标签属性中,恶意内容包含引号,从而突破属性值的限制,注入其他属性或者标签。
  4. 在标签的 href、src 等属性中,包含 javascript: 等可执行代码。
  5. 在 onload、onerror、onclick 等事件中,注入不受控制代码。
  6. 在 style 属性和标签中,包含类似 background-image:url(“javascript:…”); 的代码(新版本浏览器已经可以防范)。
  7. 在 style 属性和标签中,包含类似 expression(…) 的 CSS 表达式代码(新版本浏览器已经可以防范)。

    如何预防

    纯前端渲染(不要用jsp)

    纯前端渲染的过程:

  8. 浏览器先加载一个静态 HTML,此 HTML 中不包含任何跟业务相关的数据。

  9. 然后浏览器执行 HTML 中的 JavaScript。
  10. JavaScript 通过 Ajax 加载业务数据,调用 DOM API 更新到页面上。

在纯前端渲染中,我们会明确的告诉浏览器:下面要设置的内容是文本(.innerText),还是属性(.setAttribute),还是样式(.style)等等。浏览器不会被轻易的被欺骗,执行预期外的代码了。

但纯前端渲染还需注意避免 DOM 型 XSS 漏洞(例如 onload 事件和 href 中的 javascript:xxx 等

在很多内部、管理系统中,采用纯前端渲染是非常合适的。但对于性能要求高,或有 SEO 需求的页面,我们仍然要面对拼接 HTML 的问题。

转义 HTML

Content Security Policy

严格的 CSP 在 XSS 的防范中可以起到以下的作用:

  • 禁止加载外域代码,防止复杂的攻击逻辑。
  • 禁止外域提交,网站被攻击后,用户的数据不会泄露到外域。
  • 禁止内联脚本执行(规则较严格,目前发现 GitHub 使用)。
  • 禁止未授权的脚本执行(新特性,Google Map 移动版在使用)。
  • 合理使用上报可以及时发现 XSS,利于尽快修复问题。

    输入内容长度控制

    对于不受信任的输入,都应该限定一个合理的长度。虽然无法完全防止 XSS 发生,但可以增加 XSS 攻击的难度。

    HTTP-only Cookie

    禁止 JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注入后也无法窃取此 Cookie。

    总结

  • 利用模板引擎 开启模板引擎自带的 HTML 转义功能。例如: 在 ejs 中,尽量使用 <%= data %> 而不是 <%- data %>; 在 doT.js 中,尽量使用 {{! data } 而不是 {{= data }; 在 FreeMarker 中,确保引擎版本高于 2.3.24,并且选择正确的 freemarker.core.OutputFormat。

  • 避免内联事件 尽量不要使用 onLoad=”onload(‘{{data}}’)”、onClick=”go(‘{{action}}’)” 这种拼接内联事件的写法。在 JavaScript 中通过 .addEventlistener() 事件绑定会更安全。
  • 避免拼接 HTML 前端采用拼接 HTML 的方法比较危险,如果框架允许,使用 createElement、setAttribute 之类的方法实现。或者采用比较成熟的渲染框架,如 Vue/React 等。
  • 时刻保持警惕 在插入位置为 DOM 属性、链接等位置时,要打起精神,严加防范。
  • 增加攻击难度,降低攻击后果 通过 CSP、输入长度配置、接口安全措施等方法,增加攻击的难度,降低攻击的后果。
  • 主动检测和发现 可使用 XSS 攻击字符串和自动扫描工具寻找潜在的 XSS 漏洞。