You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Security 3.0中如何实现CSRF防护(无法升级Spring版本)

Hey there, I totally get your frustration—Spring Security 3.0 doesn’t have the built-in <csrf> tag or automatic CSRF protection that later versions offer, and being stuck in an enterprise environment with no immediate upgrade path makes this trickier. Let’s walk through a manual implementation that works with your Spring 3, Java 8, and JBoss 5 setup.

Manual CSRF Protection for Spring Security 3.0

Since the framework doesn’t handle this out of the box, we’ll build the protection in three key steps: generating a CSRF token, injecting it into your forms, and validating it on incoming requests.

1. Generate & Store CSRF Tokens in the Session

First, we need a way to create a unique CSRF token for each user session and store it securely. You can add this logic to a utility class or a request interceptor:

import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

public class CsrfTokenManager {
    private static final String CSRF_SESSION_KEY = "_csrf";

    public static String getOrGenerateCsrfToken(HttpServletRequest request) {
        HttpSession session = request.getSession();
        String csrfToken = (String) session.getAttribute(CSRF_SESSION_KEY);
        
        // Generate a new token if none exists in the session
        if (csrfToken == null) {
            csrfToken = UUID.randomUUID().toString();
            session.setAttribute(CSRF_SESSION_KEY, csrfToken);
        }
        return csrfToken;
    }
}

To ensure a token is always available, you can add this to a Spring HandlerInterceptor that runs on every request:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class CsrfTokenInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        CsrfTokenManager.getOrGenerateCsrfToken(request);
        return true;
    }
}

Register the interceptor in your Spring MVC config:

<mvc:interceptors>
    <bean class="com.yourcompany.web.interceptor.CsrfTokenInterceptor"/>
</mvc:interceptors>

2. Inject the Token into Forms & AJAX Requests

Next, you need to include the CSRF token in all requests that modify data (POST/PUT/DELETE).

For HTML Forms

Add a hidden input field to every form that uses a non-safe HTTP method:

<form method="post" action="/submit-form">
    <!-- CSRF Token -->
    <input type="hidden" name="_csrf" value="${sessionScope._csrf}"/>
    
    <!-- Your form fields here -->
    <input type="text" name="username"/>
    <button type="submit">Submit</button>
</form>

For AJAX Requests

If your app uses AJAX, send the token in a request header (e.g., X-CSRF-Token). You can pull it from the session or a meta tag:

<!-- Add this meta tag in your base template -->
<meta name="_csrf" content="${sessionScope._csrf}"/>

Then in your JavaScript:

const csrfToken = document.querySelector('meta[name="_csrf"]').content;

fetch('/api/update-data', {
    method: 'POST',
    headers: {
        'X-CSRF-Token': csrfToken,
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({ data: 'example' })
});

3. Validate the Token with a Custom Filter

Create a Spring OncePerRequestFilter to check the CSRF token on non-safe requests. This filter will sit in the Spring Security chain to block invalid requests:

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.filter.OncePerRequestFilter;

public class CsrfValidationFilter extends OncePerRequestFilter {
    private static final String CSRF_PARAM_NAME = "_csrf";
    private static final String CSRF_HEADER_NAME = "X-CSRF-Token";
    private static final String CSRF_SESSION_KEY = "_csrf";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        
        // Skip validation for safe HTTP methods (GET/HEAD/OPTIONS)
        String method = request.getMethod();
        if ("GET".equalsIgnoreCase(method) || "HEAD".equalsIgnoreCase(method) || "OPTIONS".equalsIgnoreCase(method)) {
            filterChain.doFilter(request, response);
            return;
        }

        // Get token from session
        String sessionToken = (String) request.getSession().getAttribute(CSRF_SESSION_KEY);
        if (sessionToken == null) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN, "CSRF Token not found in session");
            return;
        }

        // Get token from request (either parameter or header)
        String requestToken = request.getParameter(CSRF_PARAM_NAME);
        if (requestToken == null) {
            requestToken = request.getHeader(CSRF_HEADER_NAME);
        }

        // Validate tokens match
        if (requestToken == null || !sessionToken.equals(requestToken)) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid or missing CSRF Token");
            return;
        }

        // Continue with the filter chain if valid
        filterChain.doFilter(request, response);
    }
}

Register this filter in your Spring Security XML config, placing it before the form login filter to catch invalid requests early:

<http auto-config="true">
    <!-- Register custom CSRF filter -->
    <custom-filter ref="csrfValidationFilter" before="FORM_LOGIN_FILTER"/>
    
    <!-- Your existing security rules here -->
    <intercept-url pattern="/**" access="ROLE_USER"/>
</http>

<beans:bean id="csrfValidationFilter" class="com.yourcompany.security.CsrfValidationFilter"/>

Key Notes

  • Token Expiry: The token will expire when the user’s session expires (default JBoss session settings apply). You can add logic to rotate tokens on each request if needed for extra security.
  • Edge Cases: Make sure to cover all non-safe requests—including those from third-party libraries or hidden forms.
  • Upgrade Path: Using the _csrf key matches later Spring Security versions, so if you upgrade eventually, you can easily replace this manual implementation with the built-in one.

内容的提问来源于stack exchange,提问作者Beth

火山引擎 最新活动