wordpress主题 推荐,搜索引擎优化包括以下哪些内容,网站页面设计成品下载,什么信息发布型网站在互联网应用中#xff0c;安全性问题是开发者必须时刻关注的核心内容之一。跨站请求伪造#xff08;Cross-Site Request Forgery, CSRF#xff09;#xff0c;是一种常见的Web安全漏洞。通过CSRF攻击#xff0c;黑客可以冒用受害者的身份#xff0c;发送恶意请求#x…在互联网应用中安全性问题是开发者必须时刻关注的核心内容之一。跨站请求伪造Cross-Site Request Forgery, CSRF是一种常见的Web安全漏洞。通过CSRF攻击黑客可以冒用受害者的身份发送恶意请求执行诸如转账、订单提交等操作导致严重的安全后果。
本文将详细讲解CSRF攻击的原理及其防御方法结合电商交易系统的场景给出错误和正确的示范代码并分析常见的安全问题与解决方案帮助开发者全面理解和防御CSRF攻击。
1. CSRF攻击概述
1.1 CSRF的原理
CSRF攻击是指黑客通过欺骗用户在不知情的情况下向受信任的服务器发送请求从而执行用户并未授权的操作。由于浏览器的同源策略浏览器会自动携带当前登录用户的身份凭证如Cookie导致服务器误以为请求是合法用户发出的。
常见的CSRF攻击流程如下
用户登录电商系统并在浏览器中保持会话比如通过Cookie保存登录状态。攻击者构造一个恶意网站诱导用户访问该网站。恶意网站通过用户的浏览器向电商系统发送请求例如提交订单、修改账户信息等。由于用户已经登录服务器在收到请求时会认为是合法请求从而执行攻击者的恶意操作。
1.2 CSRF的危害
账户盗用攻击者可以伪造请求进行账户操作如修改密码、转账等。资金损失在电商交易系统中CSRF可以被用来提交伪造订单、篡改收货地址、转移资金等。信息泄露攻击者可能通过CSRF请求获取用户的敏感信息。
2. 电商交易系统中的CSRF攻击示例
为了更直观地理解CSRF攻击的危害我们以电商交易系统为例演示错误的代码实现以及如何修复它。
2.1 错误示范未防护CSRF的订单提交
在一个简单的电商交易系统中用户可以通过提交订单来购买商品。假设服务器端的订单提交接口是通过POST请求进行的代码如下
// 订单提交控制器
PostMapping(/submitOrder)
public String submitOrder(RequestParam(productId) String productId, RequestParam(quantity) int quantity,HttpSession session) {// 获取当前用户信息User user (User) session.getAttribute(currentUser);// 创建订单Order order new Order();order.setUserId(user.getId());order.setProductId(productId);order.setQuantity(quantity);// 保存订单到数据库orderService.saveOrder(order);return orderSuccess;
}这种实现存在明显的安全问题攻击者可以诱导用户访问恶意链接从而提交伪造的订单。
例如攻击者可以构造如下HTML页面并诱导用户点击
html
bodyform actionhttp://ecommerce.com/submitOrder methodPOSTinput typehidden nameproductId value123input typehidden namequantity value10input typesubmit valueSubmit order/form
/body
/html如果用户在登录状态下点击了该页面的提交按钮电商系统将生成一个伪造的订单而用户对此一无所知。
2.2 错误示范CSRF攻击的真实危害
在实际的电商系统中攻击者可能会诱导用户执行更为严重的操作比如修改收货地址、提交高价商品订单等。这些操作可以通过隐藏的表单字段自动完成用户根本不需要手动提交。
2.3 CSRF防御的基本原则
防御CSRF攻击的核心在于服务器能够验证每一个请求的合法性。一般来说CSRF防御的主要手段有
Token校验为每一个请求生成一个唯一的Token服务器通过该Token判断请求是否合法。Referer验证通过检查HTTP请求头中的Referer字段验证请求是否来自合法的页面。SameSite Cookie通过设置Cookie的SameSite属性限制跨站点的请求携带Cookie。
3. Token防护CSRF
3.1 使用Token防护CSRF
Token校验是防护CSRF攻击最常用且最有效的方法。它的工作原理是
在表单页面加载时服务器生成一个唯一的Token并将其嵌入到表单中。用户提交表单时Token会一同提交到服务器。服务器接收到请求后会验证该Token是否与会话中的Token一致只有匹配时才允许执行后续操作。
以下是如何通过Token防护CSRF攻击的示例。
3.2 在表单中添加CSRF Token
首先我们需要为每一个请求生成唯一的Token并在提交时携带该Token。以下是Spring Boot中的CSRF防护机制的实现。 生成CSRF Token Spring Security默认提供了CSRF防护机制。我们可以通过以下配置启用它 Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf() // 开启CSRF防护.and().authorizeRequests().antMatchers(/submitOrder).authenticated() // 需要登录.and().formLogin().loginPage(/login).permitAll();}
}Spring Security会自动为每个页面生成一个CSRF Token并将该Token嵌入到页面中的隐藏字段或HTTP头中。 在表单中添加CSRF Token Spring Security会在每个表单中自动包含一个CSRF Token。表单代码如下 form action/submitOrder methodPOSTinput typehidden name_csrf value${_csrf.token}/ !-- 自动生成的CSRF Token --input typetext nameproductId placeholderProduct ID/input typenumber namequantity placeholderQuantity/input typesubmit valueSubmit Order/
/form服务器端验证CSRF Token 当用户提交表单时Spring Security会自动验证CSRF Token。如果Token验证失败将会抛出异常阻止请求的执行。
3.3 限制 CSRF Token 的有效期
在 CSRF 防护机制中限制 Token 的有效期可以通过以下步骤实现
生成带有时间戳的 Token CSRF Token 在生成时附加一个时间戳以标识其生成的时间。校验 Token 时检查有效期 在验证 CSRF Token 的同时检查其时间戳是否在允许的时间范围内过期的 Token 将视为无效要求用户重新提交表单或刷新页面。
3.3.1 生成带时间戳的 CSRF Token
在生成 CSRF Token 时我们可以在 Token 中附加一个时间戳来记录生成时间。例如可以通过 base64 编码将随机生成的 Token 和当前时间戳一起组合。
import java.util.Base64;
import java.util.Date;public class CsrfTokenGenerator {private static final long TOKEN_VALIDITY 5 * 60 * 1000; // Token 有效期为 5 分钟// 生成带时间戳的 CSRF Tokenpublic static String generateCsrfToken() {String token generateRandomToken(); // 生成随机Tokenlong timestamp System.currentTimeMillis(); // 获取当前时间戳String tokenWithTimestamp token : timestamp;return Base64.getEncoder().encodeToString(tokenWithTimestamp.getBytes()); // Base64 编码}private static String generateRandomToken() {// 此处生成随机 Token简单示例为随机UUIDreturn java.util.UUID.randomUUID().toString();}
}3.3.2 验证带时间戳的 CSRF Token
在服务器端对 Token 进行验证时除了常规的 Token 匹配还需要校验时间戳确保 Token 在有效期内。
import java.util.Base64;public class CsrfTokenValidator {private static final long TOKEN_VALIDITY 5 * 60 * 1000; // 5 分钟有效期public static boolean validateCsrfToken(String token) {try {// 解码 TokenString decodedToken new String(Base64.getDecoder().decode(token));String[] parts decodedToken.split(:);if (parts.length ! 2) {return false; // Token 格式错误}String csrfToken parts[0]; // 获取CSRF Tokenlong timestamp Long.parseLong(parts[1]); // 获取时间戳long currentTime System.currentTimeMillis();if (currentTime - timestamp TOKEN_VALIDITY) {return false; // Token 已过期}// 验证Token本身的正确性与Session中的Token对比return csrfToken.equals(getStoredToken()); // 假设getStoredToken()获取服务器端存储的Token} catch (Exception e) {return false; // 解码或校验失败}}private static String getStoredToken() {// 这里从服务器Session或者数据库中获取已存储的CSRF Tokenreturn stored-token-example;}
}3.3.3 CSRF Token 使用中的代码示例
在电商交易系统的具体示例中假设用户进行购物车的结算操作。我们可以通过 CSRF Token 限制请求的有效期防止攻击者在很久之前窃取的 Token 被再次利用。
前端发送请求
function checkout() {let csrfToken getCookie(CSRF-TOKEN);fetch(/checkout, {method: POST,headers: {X-CSRF-TOKEN: csrfToken, // 包含CSRF TokenContent-Type: application/json},body: JSON.stringify({productId: 123,amount: 1})}).then(response {if (response.status 403) {alert(CSRF Token 过期或无效请刷新页面再试);}});
}
服务器端验证
在服务器端通过 CsrfTokenValidator 对 Token 进行验证确保其没有过期。
PostMapping(/checkout)
public ResponseEntityString checkout(RequestHeader(X-CSRF-TOKEN) String csrfToken) {if (!CsrfTokenValidator.validateCsrfToken(csrfToken)) {return new ResponseEntity(CSRF Token 无效或已过期, HttpStatus.FORBIDDEN);}// 处理购物车结算逻辑return new ResponseEntity(结算成功, HttpStatus.OK);
}
3.3.4 刷新过期 Token
如果用户的 CSRF Token 过期前端可以通过一个特定的 API 进行 Token 刷新重新获取有效的 CSRF Token。
GetMapping(/refreshCsrfToken)
public ResponseEntityString refreshCsrfToken(HttpServletResponse response) {String newToken CsrfTokenGenerator.generateCsrfToken();Cookie csrfCookie new Cookie(CSRF-TOKEN, newToken);csrfCookie.setPath(/);csrfCookie.setHttpOnly(true);response.addCookie(csrfCookie);return new ResponseEntity(CSRF Token 已刷新, HttpStatus.OK);
}
3.3.5 Token 过期处理的优点
安全性增强即使攻击者获取到 CSRF Token也只能在有限的时间内进行攻击。防止 Token 被长期滥用定期刷新 Token防止长期使用相同的 Token 增加攻击风险。
4. 使用Referer头验证
另一种防护CSRF攻击的方式是检查HTTP请求头中的Referer字段验证请求是否来自同一个网站。虽然Referer验证并不是100%可靠因为可能被用户代理修改但可以作为一种补充手段。
我们可以通过Spring Security提供的Referer验证器实现这一机制
Override
protected void configure(HttpSecurity http) throws Exception {http.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher(/submitOrder)).and().authorizeRequests().antMatchers(/submitOrder).authenticated();
}通过这种方式服务器会检查请求的来源如果请求的来源不是本站域名则拒绝执行该请求。
5. 同源检测SameSite Cookie
通过设置 cookie 的 SameSite 属性可以防止跨站点请求时浏览器发送 cookie从而减少 CSRF 攻击的风险。
SameSiteLax: 允许导航链接发送 cookie但跨站点 POST 请求不会发送 cookie。SameSiteStrict: 完全禁止跨站点的请求发送 cookie最大限度地防御 CSRF。
Cookie 设置示例
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().addFilterBefore(new CsrfFilter(csrfTokenRepository), UsernamePasswordAuthenticationFilter.class).headers().frameOptions().sameOrigin().httpStrictTransportSecurity().includeSubDomains(true).and().cookie().sameSite(SameSiteCookieAttributeValue.LAX);
6. 总结
本文详细介绍了CSRF攻击的原理和危害并通过错误与正确示范演示了如何防护CSRF攻击。CSRF攻击是一种常见且危险的安全漏洞开发者应时刻保持警惕采用诸如Token验证、Referer检查、SameSite Cookie等多层防护手段确保Web应用的安全性。
通过掌握这些防护技巧开发者可以有效抵御CSRF攻击保护用户的个人信息与财产安全。在实际开发中安全问题应始终放在优先位置只有不断优化和完善才能打造出安全、可靠的应用系统。