java - Spring MVC中的CSRF(跨站请求伪造)保护

标签 java spring-mvc spring-security csrf csrf-protection

我对 Spring 的 CSRF(跨站请求伪造)保护有点困惑。不,我有我的 jsp、我的 Controller 和网络服务。我想要做的是在 Web 服务级别验证 token ,如果 token 匹配,则运行 Web 服务(在我的例子中执行数据库插入)

JSP 文件

    <form:input type="text" class="form-control" path="mName" />

    <input type="hidden" name="${_csrf.parameterName}"
        value="${_csrf.token}" />

    <div class="form-action">
        <input type="submit" value="Save" class="btn btn-primary" />
    </div>
</form:form>

我也插入了隐藏标签。现在我应该怎么做来验证这个 token 。我在那里有点迷路。

在 Controller 类中,我从表单获取值到对象并调用网络服务来保存数据

@RequestMapping(method = RequestMethod.POST)
  public String processForm(@ModelAttribute(value = "userForm") @Valid UserForm userForm, BindingResult result, ModelMap model) {      

   //call the web service
  }

最佳答案

OWASP Enterprise Security API有一个很好的选择,可以提供针对 CSRF 的可靠保护。 CSRF 其实很容易解决。 OWASP ESAPI 提供了如下规范来实现 CSRF 保护。

1. Generate new CSRF token and add it to user once on login and store user in http session.

这是在默认的 ESAPI 实现中完成的,它存储为 User 对象的成员变量,该对象存储在 session 中。

/this code is in the DefaultUser implementation of ESAPI
/** This user's CSRF token. */
private String csrfToken = resetCSRFToken();
...
public String resetCSRFToken() {
    csrfToken = ESAPI.randomizer().getRandomString(8, DefaultEncoder.CHAR_ALPHANUMERICS);
    return csrfToken;
}

2. On any forms or urls that should be protected, add the token as a parameter / hidden field.

下面的addCSRFToken 方法应该被调用用于将要呈现的任何需要 CSRF 保护的 url。或者,如果你正在创建一个表单,或者有另一种呈现 URL 的技术(比如 c:url),那么一定要添加一个名为“ctoken”的参数或隐藏字段>"和 DefaultHTTPUtilities.getCSRFToken() 的值。

//from HTTPUtilitiles interface
final static String CSRF_TOKEN_NAME = "ctoken";
//this code is from the DefaultHTTPUtilities implementation in ESAPI
public String addCSRFToken(String href) {
    User user = ESAPI.authenticator().getCurrentUser();
    if (user.isAnonymous()) {
        return href;
    }
    // if there are already parameters append with &, otherwise append with ?
    String token = CSRF_TOKEN_NAME + "=" + user.getCSRFToken();
    return href.indexOf( '?') != -1 ? href + "&" + token : href + "?" + token;
}
...
public String getCSRFToken() {
    User user = ESAPI.authenticator().getCurrentUser();
    if (user == null) return null;
    return user.getCSRFToken();
}

3. On the server side for those protected actions, check that the submitted token matches the token from the user object in the session.

确保您从 servletspring 操作或 jsf Controller 或您使用的任何服务器端机制调用此方法处理请求。这应该在您需要验证 CSRF 保护的任何请求时调用。请注意,当 token 不匹配时,它被认为是可能的伪造请求。

//this code is from the DefaultHTTPUtilities implementation in ESAPI
public void verifyCSRFToken(HttpServletRequest request) throws IntrusionException {
    User user = ESAPI.authenticator().getCurrentUser();
    // check if user authenticated with this request - no CSRF protection required
    if( request.getAttribute(user.getCSRFToken()) != null ) {
        return;
    }
    String token = request.getParameter(CSRF_TOKEN_NAME);
    if ( !user.getCSRFToken().equals( token ) ) {
        throw new IntrusionException("Authentication failed", "Possibly forged HTTP request without proper CSRF token detected");
    }
}

4. On logout and session timeout, the user object is removed from the session and the session destroyed.

在这一步中,调用了注销。发生这种情况时,请注意 session 已失效,当前用户对象将重置为匿名用户,从而删除对当前用户的引用以及相应的 csrf token 。

//this code is in the DefaultUser implementation of ESAPI
public void logout() {
    ESAPI.httpUtilities().killCookie( ESAPI.currentRequest(), ESAPI.currentResponse(), HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME );
    HttpSession session = ESAPI.currentRequest().getSession(false);
    if (session != null) {
        removeSession(session);
        session.invalidate();
    }
    ESAPI.httpUtilities().killCookie(ESAPI.currentRequest(), ESAPI.currentResponse(), "JSESSIONID");
    loggedIn = false;
    logger.info(Logger.SECURITY_SUCCESS, "Logout successful" );
    ESAPI.authenticator().setCurrentUser(User.ANONYMOUS);
}

来源:http://www.jtmelton.com/2010/05/16/the-owasp-top-ten-and-esapi-part-6-cross-site-request-forgery-csrf/

希望这对你有帮助。

希希尔

关于java - Spring MVC中的CSRF(跨站请求伪造)保护,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22555110/

相关文章:

java - IntelliJ IDEA 中的原型(prototype)列表来自哪里?

java - Spring 数据 Autowiring 数据库连接无法通过 JUnit 测试

java - 当无效的承载 token 发送到后端时如何记录

java - @EnableHypermediaSupport 的 XML 配置等效项

java - 通过 XPATH 查找没有特定父节点的节点

java - Spring - 拦截 bean 创建和注入(inject)自定义代理

java - 使用 Spring 测试框架模拟服务的预期结果

java - 我可以/应该用 spring security 中的每个请求刷新 OAuth2 token 吗

java - 在 user-service-ref 中使用 jdbc-user-service

java - 在 Scala 中通过 SimpleDateFormat 转换后如何保持 DateTime 为 DateTime 格式?