CSRF全称Cross Site Request Forgery,中文是跨站请求伪造。

Spring Security结合Thymeleaf templates,会在form中加入隐藏字段(token),从而减缓csrf威胁。

依赖配置

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
</dependencies

定制后的表单

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
    <body>
        <form method="post" th:action="@{/jwt-csrf-form}">
            <input type="submit" class="btn btn-primary" value="Click Me!"/>
        </form>
    </body>
</html>

xmlns:thth:action 可以让Spring Security触发,从而注入token

JWT

通过JWT改进token

首先,配置依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>${jjwt.version}</version>
</dependency>

生成jwt token

@Override
public CsrfToken generateToken(HttpServletRequest request) {
    String id = UUID.randomUUID().toString().replace("-", "");


    Date now = new Date();
    Date exp = new Date(now.getTime() + (1000*30)); // 30 seconds


    String token = Jwts.builder()
        .setId(id)
        .setIssuedAt(now)
        .setNotBefore(now)
        .setExpiration(exp)
        .signWith(SignatureAlgorithm.HS256, secret)
        .compact();


    return new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", token);
}

csrf token验证器

// CsrfFilter already made sure the token matched. Here, we'll make sure it's not expired
try {
    Jwts.parser()
        .setSigningKeyResolver(secretService.getSigningKeyResolver())
        .parseClaimsJws(token.getToken());
} catch (JwtException e) {
    // most likely an ExpiredJwtException, but this will handle any
    request.setAttribute("exception", e);
    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
    RequestDispatcher dispatcher = request.getRequestDispatcher("expired-jwt");
    dispatcher.forward(request, response);
}

配置spring security

protected void configure(HttpSecurity http) throws Exception {
    http
        .addFilterAfter(new JwtCsrfValidatorFilter(), CsrfFilter.class)
        .csrf()
            .csrfTokenRepository(jwtCsrfTokenRepository)
            .ignoringAntMatchers(ignoreCsrfAntMatchers)
        .and()
        .authorizeRequests()
            .antMatchers("/**")
            .permitAll();
}

results matching ""

    No results matching ""