XSS攻击原理
XSS(Cross-Site Scripting,跨站脚本攻击)是一种常见的网络攻击方式。攻击者通过在受害者的浏览器中注入恶意脚本,来实现对受害者的会话劫持、敏感信息窃取等非法目的。但是在实际的项目开发中,除了少数企业外绝大多数公司的项目开发流程并不规范,关于安全更很少考虑,都是从服务端结合数据存储去处理请求。
XSS攻击主要分为以下几种类型:
-
反射型XSS:反射型XSS攻击是一种非持久性的攻击,它发生在恶意脚本从服务器端反射到客户端的过程中,通常涉及到用户通过点击一个链接或访问一个页面时,服务器端未经充分验证和转义的输入被直接输出到HTML中。
-
存储型XSS:又称为持久性xss,这种攻击一般在第三方欺诈网站上,恶意脚本存储于服务器端,如数据库、消息论坛等,当用户请求一个包含恶意脚本的页面时,服务器将恶意脚本发送给用户,执行攻击。
-
DOM-based型XSS:恶意脚本完全在客户端执行,不涉及服务器端。攻击者通过操纵DOM结构,诱导浏览器执行恶意脚本,这种攻击也是我们比较常见,也是比较隐蔽的,因为攻击者不需要在服务器端插入恶意脚本。用来获取cookie等用户信息。
XSS防范措施
-
输入验证:对所有用户输入进行验证,不允许非法输入。例如,可以使用白名单来限制输入内容,只允许预期内的字符和格式。
-
输出编码:对输出数据进行编码,确保任何在HTML、JavaScript等中的用户数据都被正确地转义。这样可以避免恶意脚本被浏览器解释和执行。
-
HTML编码:例如,将
<
转换为<
,将>
转换为>
。 -
JavaScript编码:将
<
转换为\u003c
,将>
转换为\u003e
等。 -
URL编码:将特殊字符转换为
%
后跟两位十六进制数。 -
CSS编码:如将
url
属性中的特殊字符进行转义。
-
-
使用HTTP响应头:设置
X-XSS-Protection
为1; mode=block
,可以使得浏览器在检测到XSS攻击时停止渲染页面。不过现代浏览器加入了 “内容安全策略CSP”,而且X-XSS-Protection主要针对反射型 XSS 攻击有效,对存储型或基于 DOM 的 XSS 攻击的防护能力有限。可能会将合法的网站功能识别为 XSS 攻击,导致正常内容被屏蔽。 -
实施内容安全策略(CSP):通过设置HTTP响应头中的内容安全策略CSP, Content-Security-Policy,可以指定哪些动态资源可以执行,从而阻止未授权的脚本执行,现代浏览器基本都支持。
-
使用安全的框架和库:许多现代Web框架提供了内置的防护机制,如ASP.NET的Anti-XSS库。
代码示例
以下是一个简单的Java过滤器示例,用于防范存储型XSS攻击:
@WebFilter("/page-url/*")
public class XSSFilter implements Filter {public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse res = (HttpServletResponse) response;chain.doFilter(req, res);String Referer = req.getHeader("Referer");if (Referer != null && Referer.contains("badScript")) {res.getWriter().write("You are trying to use XSS attacks, aren't you?");}}
}
解决方案
- 针对反射型XSS:确保所有动态内容都通过参数化查询,并实施输出编码。具体防范可以在开发中考虑一些输入验证、输出转义比如使用HTML实体编码来转义特殊字符,将 < 转换为 <,将 > 转换为 >。
- 针对存储型XSS:对所有用户输入进行验证和编码,并保持对所有存储数据的警惕,定期进行安全审计。具体操作有验证和转义输入数据、实施安全的编程实践比如避免使用 eval 和 innerHTML 等可能导致XSS的API、使用存储XSS过滤器、对动态生成的内容进行适当的编码,确保任何插入到HTML页面中的数据都不会被解释为脚本。
- 针对DOM-based型XSS:确保任何动态注入的DOM内容都经过严格的验证和编码。DOM 型 XSS 攻击,实际上就是网站前端 JavaScript 代码本身不够严谨,把不可信的数据当作代码执行了。
在使用 remove]、outerHTML、removed 时要特别小心,不要把不可信的数据作为 HTML 插到页面上,而应尽量使用 .textContent、.setAttribute()设置内容的函数或者方法来替代插入dom片段等方法来规避这个问题。
如果用 Vue/React 技术栈框架,并且不使用 v-html/dangerouslySetInnerHTML 功能,就在前端 render 阶段避免 innerHTML、outerHTML 的 XSS 隐患。
DOM 中的内联事件监听器,如 location、onclick、onerror、onload、onmouseover等, 标签的 href 属性,JavaScript 的 eval()、setTimeout()、setInterval() 等,都能把字符串作为代码运行。如果不可信的数据拼接到字符串中传递给这些 API,很容易产生安全隐患,请务必避免。
通过实施上述措施,可以大幅提高Web应用的安全性,防止XSS攻击带来的危害。在开发过程中应持续关注安全最佳实践,最好能形成一套固定的方案来长期优化和维护,并定期进行安全测试和评估。