当前位置: 首页 > ops >正文

CSRF和XSS攻击防御指南

目录

  1. CSRF和XSS攻击介绍
    • CSRF攻击
    • XSS攻击
    • CSRF与XSS的区别与联系
  2. Java项目中的防御措施
    • CSRF攻击防御措施
    • XSS攻击防御措施
    • 综合安全措施
  3. 代码示例
    • CSRF防御代码示例
    • XSS防御代码示例
    • 综合安全配置示例

CSRF和XSS攻击介绍

CSRF攻击

CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种常见的Web安全漏洞,攻击者通过诱导用户在已认证的Web应用上执行非预期的操作。这种攻击利用了Web应用对用户身份验证的信任机制,使得应用无法区分是否为用户本人发起的合法请求。

CSRF攻击的工作原理相对简单但极具威胁性。当用户登录某个网站并获得认证后(通常通过cookie或session),浏览器会在每次请求该网站时自动附带认证信息。攻击者可以构造一个恶意页面,当受害用户访问该页面时,页面会自动向已认证的网站发送请求,而这些请求会带上用户的认证信息,使服务器误认为是用户本人的操作。

一个典型的CSRF攻击场景如下:假设用户已登录银行网站,银行转账API的URL为https://bank.example/transfer?to=account&amount=1000。攻击者可以创建一个包含以下内容的恶意网页:

<img src="https://bank.example/transfer?to=attacker&amount=1000" style="display:none">

当用户访问这个恶意页面时,浏览器会尝试加载这个"图片",实际上是向银行网站发送了一个转账请求,而由于用户已登录,该请求会带上用户的认证信息,导致转账操作被执行。

CSRF攻击的危害包括但不限于:

  • 未经授权的资金转账
  • 修改用户账户信息(如密码、邮箱)
  • 发布未经授权的内容
  • 执行管理员级别的操作

XSS攻击

XSS(Cross-Site Scripting,跨站脚本)是另一种常见且危险的Web安全漏洞,攻击者通过在目标网站上注入恶意脚本代码,当其他用户浏览该网站时,这些恶意脚本会在用户的浏览器中执行。

XSS攻击主要分为三种类型:

  1. 存储型XSS(Stored XSS):恶意脚本被永久存储在目标服务器上(如数据库、留言板、评论区),当用户请求包含此脚本的页面时,脚本会被执行。这是最危险的XSS类型,因为影响范围广泛且持久。

  2. 反射型XSS(Reflected XSS):恶意脚本包含在请求中,然后被服务器"反射"回响应页面。通常通过诱导用户点击特制的URL来触发,如:

    https://example.com/search?q=<script>alert('XSS')</script>
    

    如果网站直接将搜索词输出到页面而不进行过滤,脚本将在用户浏览器中执行。

  3. DOM型XSS(DOM-based XSS):漏洞存在于客户端代码中,恶意脚本通过修改页面的DOM环境在本地执行,而不经过服务器。

XSS攻击的危害极大,包括:

  • 窃取用户的Cookie和会话信息
  • 监控用户行为(如键盘记录)
  • 修改网页内容进行钓鱼
  • 利用用户身份执行操作
  • 在用户浏览器中执行任意JavaScript代码

CSRF与XSS的区别与联系

虽然CSRF和XSS都是Web安全攻击,但它们的原理和防御方法有明显区别:

区别

  • CSRF利用的是网站对用户浏览器的信任,攻击者不需要获取用户的任何敏感信息,只需诱导用户访问恶意页面。
  • XSS利用的是用户对网站的信任,通过在可信网站上注入恶意代码来攻击用户。
  • CSRF主要是伪造用户请求,而XSS是在用户浏览器中执行恶意代码。
  • CSRF通常需要用户已登录目标网站,而XSS不一定需要。

联系

  • XSS可以用来辅助CSRF攻击,通过XSS注入的脚本可以绕过一些CSRF防护措施。
  • 两种攻击都可能导致用户账户被劫持或执行未授权操作。
  • 两种攻击的防御都需要严格的输入验证和输出编码。

Java项目中的防御措施

CSRF攻击防御措施

在Java项目中防御CSRF攻击需要采取多层次的安全措施。以下是几种有效的防御策略:

1. 使用同步令牌模式(Synchronizer Token Pattern)

同步令牌是防御CSRF最常用且有效的方法。其原理是在服务器端生成一个随机的令牌值,并将其嵌入到表单中。当表单提交时,服务器会验证令牌的有效性。由于攻击者无法获取到这个令牌,因此无法构造有效的请求。

在Java Web应用中,可以通过以下方式实现:

  • 在会话开始时生成CSRF令牌并存储在服务器端(通常是Session中)
  • 在所有表单和AJAX请求中包含这个令牌
  • 在服务器端验证每个请求中的令牌
2. 使用SameSite Cookie属性

现代浏览器支持为Cookie设置SameSite属性,这可以限制Cookie在跨站请求中的发送。设置为"Strict"或"Lax"可以有效防止CSRF攻击。在Java应用中,可以通过以下方式设置:

  • 在响应头中设置Cookie的SameSite属性
  • 使用Servlet API或框架特定的方法配置Cookie属性
3. 检查Referer和Origin头

虽然不应该仅依赖这种方法,但检查HTTP请求的Referer和Origin头可以作为额外的防御层。服务器可以验证这些头部是否来自预期的域。

4. 使用自定义请求头

对于AJAX请求,可以添加自定义头部,由于同源策略的限制,攻击者无法在跨域请求中添加自定义头部。

5. 使用框架内置的CSRF保护

许多Java Web框架都提供了内置的CSRF保护机制:

  • Spring Security:提供了完整的CSRF保护实现
  • Java EE/Jakarta EE:可以通过过滤器实现CSRF保护
  • Apache Struts:提供了内置的CSRF拦截器

XSS攻击防御措施

防御XSS攻击需要严格控制用户输入和输出,以下是Java项目中的主要防御措施:

1. 输入验证和净化

所有用户输入都应该经过严格验证和净化,包括:

  • 验证数据类型、长度、格式和范围
  • 拒绝包含可疑脚本的输入
  • 使用白名单而非黑名单进行验证
  • 使用专门的库进行输入净化,如OWASP Java Encoder或jsoup
2. 输出编码

在将数据输出到HTML、JavaScript、CSS或URL时,必须进行适当的编码:

  • HTML内容编码:将特殊字符转换为HTML实体
  • JavaScript编码:在JavaScript上下文中转义特殊字符
  • CSS编码:在CSS上下文中转义特殊字符
  • URL编码:对URL参数进行编码
3. 使用安全的模板引擎

现代模板引擎通常提供自动转义功能,可以减少XSS风险:

  • Thymeleaf:默认对输出进行HTML转义
  • FreeMarker:支持自动转义
  • JSP:可以使用JSTL的<c:out>标签进行自动转义
4. 内容安全策略(CSP)

内容安全策略是一种浏览器安全机制,可以限制页面可以加载的资源,有效减轻XSS攻击的影响。在Java应用中,可以通过设置HTTP响应头来启用CSP:

Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com;
5. 使用安全的Cookie

设置Cookie的HttpOnly和Secure标志可以减轻XSS攻击的影响:

  • HttpOnly:防止JavaScript访问Cookie,减轻Cookie窃取的风险
  • Secure:确保Cookie只通过HTTPS连接传输
6. 使用框架的XSS保护

许多Java框架提供了内置的XSS保护:

  • Spring:提供了多种工具和配置选项来防止XSS
  • Java EE/Jakarta EE:可以使用过滤器和拦截器实现XSS防护
  • Apache Struts:提供了内置的XSS预防机制

综合安全措施

除了针对CSRF和XSS的特定防御措施外,还应采取以下综合安全措施:

1. 使用安全的HTTP响应头

配置适当的HTTP安全头可以增强应用的安全性:

  • X-XSS-Protection:启用浏览器内置的XSS过滤器
  • X-Content-Type-Options:防止MIME类型嗅探
  • X-Frame-Options:防止点击劫持攻击
  • Strict-Transport-Security:强制使用HTTPS
2. 定期安全审计和渗透测试

定期进行安全审计和渗透测试可以发现潜在的安全漏洞。可以使用自动化工具如OWASP ZAP或Burp Suite进行初步测试。

3. 保持依赖库的更新

确保所有依赖库和框架都是最新的,及时修补已知的安全漏洞。可以使用工具如OWASP Dependency Check来扫描依赖项中的已知漏洞。

4. 实施安全开发生命周期

将安全考虑融入到整个开发生命周期中,包括需求分析、设计、编码、测试和部署阶段。

5. 使用Web应用防火墙(WAF)

部署Web应用防火墙可以提供额外的保护层,过滤恶意请求并阻止常见的攻击模式。

代码示例

CSRF防御代码示例

1. Spring Security中的CSRF防御

Spring Security提供了内置的CSRF保护机制,只需简单配置即可启用:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http// 启用CSRF保护(默认已启用).csrf()// 可以自定义CSRF令牌仓库//.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())// 可以指定哪些请求需要CSRF保护//.ignoringAntMatchers("/api/public/**").and().authorizeRequests().anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll();}
}

在Thymeleaf模板中包含CSRF令牌:

<form th:action="@{/process}" method="post"><!-- CSRF令牌会自动添加 --><input type="text" name="username" /><button type="submit">提交</button>
</form>

对于AJAX请求,可以这样获取和发送CSRF令牌:

// 获取CSRF令牌
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");// 在AJAX请求中包含令牌
$(document).ajaxSend(function(e, xhr, options) {xhr.setRequestHeader(header, token);
});
2. 使用过滤器实现CSRF保护(不使用框架)

如果不使用Spring Security,可以自定义过滤器实现CSRF保护:

@WebFilter("/*")
public class CSRFFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;HttpServletResponse httpResponse = (HttpServletResponse) response;HttpSession session = httpRequest.getSession(false);// 跳过GET、HEAD、OPTIONS和TRACE请求String method = httpRequest.getMethod();if (method.equals("GET") || method.equals("HEAD") || method.equals("OPTIONS") || method.equals("TRACE")) {chain.doFilter(request, response);return;}// 检查Referer头String referer = httpRequest.getHeader("Referer");if (referer != null) {String serverName = httpRequest.getServerName();if (!referer.contains(serverName)) {httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "可能的CSRF攻击");return;}}// 检查CSRF令牌if (session != null) {String sessionToken = (String) session.getAttribute("csrf_token");String requestToken = httpRequest.getParameter("csrf_token");if (sessionToken == null || requestToken == null || !sessionToken.equals(requestToken)) {httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "CSRF令牌无效");return;}}chain.doFilter(request, response);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化代码}@Overridepublic void destroy() {// 清理代码}
}
3. 设置SameSite Cookie属性

在Servlet中设置带有SameSite属性的Cookie:

@WebServlet("/login")
public class LoginServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 验证登录凭据...// 创建会话Cookie并设置SameSite属性Cookie sessionCookie = new Cookie("JSESSIONID", request.getSession().getId());sessionCookie.setHttpOnly(true);sessionCookie.setSecure(true); // 在HTTPS环境中使用// 设置SameSite属性(Tomcat 9.0.33+或使用其他方法)response.setHeader("Set-Cookie", sessionCookie.getName() + "=" + sessionCookie.getValue() + "; HttpOnly; Secure; SameSite=Lax; Path=" + sessionCookie.getPath());response.sendRedirect("/dashboard");}
}

XSS防御代码示例

1. 使用OWASP Java Encoder进行输出编码

首先,添加OWASP Java Encoder依赖:

<dependency><groupId>org.owasp.encoder</groupId><artifactId>encoder</artifactId><version>1.2.3</version>
</dependency>

在Servlet或控制器中使用:

import org.owasp.encoder.Encode;@WebServlet("/display")
public class DisplayServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String userInput = request.getParameter("input");// 根据上下文使用不同的编码方法String htmlEncoded = Encode.forHtml(userInput);              // HTML内容String jsEncoded = Encode.forJavaScript(userInput);          // JavaScript上下文String cssEncoded = Encode.forCssString(userInput);          // CSS上下文String attrEncoded = Encode.forHtmlAttribute(userInput);     // HTML属性String uriEncoded = Encode.forUri(userInput);                // URI/URL上下文// 输出编码后的内容response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("<html><body>");out.println("<p>HTML编码: " + htmlEncoded + "</p>");out.println("<p>JavaScript编码: <script>var data = '" + jsEncoded + "';</script></p>");out.println("<p>CSS编码: <style>.user-data:after { content: '" + cssEncoded + "'; }</style></p>");out.println("<p>属性编码: <div data-user='" + attrEncoded + "'></div></p>");out.println("<p>URI编码: <a href='https://example.com?q=" + uriEncoded + "'>链接</a></p>");out.println("</body></html>");}
}
2. 使用自定义XSS过滤器

创建一个过滤器来净化所有请求参数:

@WebFilter("/*")
public class XSSFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化代码}@Overridepublic void destroy() {// 清理代码}// 自定义请求包装器,用于净化参数private class XSSRequestWrapper extends HttpServletRequestWrapper {public XSSRequestWrapper(HttpServletRequest request) {super(request);}@Overridepublic String getParameter(String name) {String value = super.getParameter(name);return value != null ? sanitize(value) : null;}@Overridepublic String[] getParameterValues(String name) {String[] values = super.getParameterValues(name);if (values == null) {return null;}String[] sanitizedValues = new String[values.length];for (int i = 0; i < values.length; i++) {sanitizedValues[i] = sanitize(values[i]);}return sanitizedValues;}@Overridepublic Map<String, String[]> getParameterMap() {Map<String, String[]> paramMap = super.getParameterMap();Map<String, String[]> sanitizedMap = new HashMap<>();for (Map.Entry<String, String[]> entry : paramMap.entrySet()) {String[] values = entry.getValue();String[] sanitizedValues = new String[values.length];for (int i = 0; i < values.length; i++) {sanitizedValues[i] = sanitize(values[i]);}sanitizedMap.put(entry.getKey(), sanitizedValues);}return sanitizedMap;}// 简单的HTML净化方法(生产环境应使用更健壮的库)private String sanitize(String value) {if (value == null) {return null;}// 替换常见的XSS向量value = value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");value = value.replaceAll("\\(", "&#40;").replaceAll("\\)", "&#41;");value = value.replaceAll("'", "&#39;");value = value.replaceAll("eval\\((.*)\\)", "");value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");value = value.replaceAll("script", "");return value;}}
}
3. 使用JSoup进行HTML净化

添加JSoup依赖:

<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.15.3</version>
</dependency>

创建HTML净化工具类:

import org.jsoup.Jsoup;
import org.jsoup.safety.Safelist;public class HTMLSanitizer {/*** 净化HTML内容,只保留安全的标签和属性* * @param html 原始HTML内容* @return 净化后的HTML*/public static String sanitize(String html) {if (html == null) {return null;}// 使用JSoup的基本净化功能return Jsoup.clean(html, Safelist.basic());}/*** 净化HTML内容,允许更多格式化标签* * @param html 原始HTML内容* @return 净化后的HTML*/public static String sanitizeRich(String html) {if (html == null) {return null;}// 使用JSoup的富文本净化功能Safelist safelist = Safelist.relaxed()// 可以添加额外允许的标签和属性.addAttributes("span", "style").addAttributes("div", "class", "id");return Jsoup.clean(html, safelist);}/*** 完全移除所有HTML标签,只保留文本内容* * @param html 原始HTML内容* @return 纯文本内容*/public static String stripAllTags(String html) {if (html == null) {return null;}return Jsoup.clean(html, Safelist.none());}
}
4. 配置内容安全策略(CSP)

创建一个过滤器来添加CSP头:

@WebFilter("/*")
public class CSPFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletResponse httpResponse = (HttpServletResponse) response;// 设置内容安全策略, 这是一个相对严格的策略,应根据实际需求调整StringBuilder cspBuilder = new StringBuilder();cspBuilder.append("default-src 'self'; ");cspBuilder.append("script-src 'self' https://cdnjs.cloudflare.com; ");cspBuilder.append("style-src 'self' https://fonts.googleapis.com 'unsafe-inline'; ");cspBuilder.append("img-src 'self' data: https:; ");cspBuilder.append("font-src 'self' https://fonts.gstatic.com; ");cspBuilder.append("connect-src 'self'; ");cspBuilder.append("media-src 'self'; ");cspBuilder.append("object-src 'none'; ");cspBuilder.append("frame-src 'self'; ");cspBuilder.append("base-uri 'self'; ");cspBuilder.append("form-action 'self'; ");httpResponse.setHeader("Content-Security-Policy", cspBuilder.toString());// 设置其他安全相关的HTTP头httpResponse.setHeader("X-Content-Type-Options", "nosniff");httpResponse.setHeader("X-Frame-Options", "SAMEORIGIN");httpResponse.setHeader("X-XSS-Protection", "1; mode=block");chain.doFilter(request, response);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化代码}@Overridepublic void destroy() {// 清理代码}
}

综合安全配置示例

Spring Boot应用的综合安全配置
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http// CSRF保护.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()// 授权规则.authorizeRequests().antMatchers("/", "/home", "/public/**").permitAll().antMatchers("/admin/**").hasRole("ADMIN").anyRequest().authenticated().and()// 登录配置.formLogin().loginPage("/login").permitAll().and()// 注销配置.logout().permitAll().and()// 安全HTTP头.headers()// XSS保护.xssProtection().block(true).and()// 内容类型选项.contentTypeOptions().and()// 框架选项(防止点击劫持).frameOptions().sameOrigin().and()// 内容安全策略.contentSecurityPolicy("default-src 'self'; script-src 'self' https://cdnjs.cloudflare.com; style-src 'self' https://fonts.googleapis.com 'unsafe-inline'").and()// HTTP严格传输安全.httpStrictTransportSecurity().includeSubDomains(true).maxAgeInSeconds(31536000).and()// 引用策略.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.SAME_ORIGIN);}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic HttpFirewall allowUrlEncodedSlashHttpFirewall() {StrictHttpFirewall firewall = new StrictHttpFirewall();firewall.setAllowUrlEncodedSlash(true);firewall.setAllowSemicolon(false);return firewall;}@Overridepublic void configure(WebSecurity web) throws Exception {web.httpFirewall(allowUrlEncodedSlashHttpFirewall());}
}
自定义XSS和CSRF过滤器链
@Configuration
public class WebConfig implements WebMvcConfigurer {@Beanpublic FilterRegistrationBean<XSSFilter> xssFilterRegistration() {FilterRegistrationBean<XSSFilter> registration = new FilterRegistrationBean<>();registration.setFilter(new XSSFilter());registration.addUrlPatterns("/*");registration.setName("xssFilter");registration.setOrder(1); // 设置过滤器顺序return registration;}@Beanpublic FilterRegistrationBean<CSRFFilter> csrfFilterRegistration() {FilterRegistrationBean<CSRFFilter> registration = new FilterRegistrationBean<>();registration.setFilter(new CSRFFilter());registration.addUrlPatterns("/*");registration.setName("csrfFilter");registration.setOrder(2); // 在XSS过滤器之后return registration;}@Beanpublic FilterRegistrationBean<CSPFilter> cspFilterRegistration() {FilterRegistrationBean<CSPFilter> registration = new FilterRegistrationBean<>();registration.setFilter(new CSPFilter());registration.addUrlPatterns("/*");registration.setName("cspFilter");registration.setOrder(3); // 在CSRF过滤器之后return registration;}
}

通过综合应用这些防御措施,可以显著提高Java Web应用的安全性,有效防御CSRF和XSS等常见的Web安全攻击。

http://www.xdnf.cn/news/9250.html

相关文章:

  • 院校机试刷题第十三天:代码随想录算法训练营第七天
  • 调不好分布式锁?HarmonyOS + Redis 分布式锁失效排查全路径
  • Oracle20200714GI_PSU补丁流程及问题收集
  • 一种比较精简的协议
  • python学习day30
  • SSTable(Sorted String Table)结构与用途详解
  • 数据类型(基本类型)day2
  • C-内存函数,动态内存
  • Qt布局连续添加控件
  • Web3怎么本地测试连接以太坊?
  • 封装文档核心知识点总结(通俗版)
  • 利用 MkDocs 和 GitHub 部署个人博客网页
  • LINUX安装运行jeelowcode后端项目(命令行)
  • 【运维自动化-标准运维】如何实现在不同步骤间传递参数
  • 人该怎样活着呢?54
  • 随机模拟专题:第一课
  • 5G网络切片技术:开启网络服务定制化新时代
  • SpringMVC注解、@Controller注解和@RestController注解的区别、@RequestMapper、@PathVariable
  • 制作一款打飞机游戏59:子弹生成
  • DeepSeek 赋能智能安防:从算法革新到场景落地的全解析
  • 4月报 | SeaTunnel支持TDengine的多表Sink功能
  • 机器学习算法-- K 近邻算法(KNN)
  • Linux 资源限制(进程级,用户级,系统级)
  • Debian 11 之使用hostapd与dnsmasq进行AP设置
  • 欧拉定理:若 gcd(a,n)=1,则 a^φ(n)≡1(mod n)。
  • 2025 吉林CCPC
  • 【数据结构】 时间复杂度
  • 浙大版《Python 程序设计》题目集6-3,6-4,6-5,6-6列表或元组的数字元素求和及其变式(递归解法)
  • 前端生成UUID
  • 5.27 打卡