mirror of https://github.com/halo-dev/halo
Xor CSRF token (#6798)
#### What type of PR is this? /kind improvement /area core /milestone 2.20.x #### What this PR does / why we need it: This PR makes XOR operation for CSRF token and changes the CSRF cookie `HttpOnly` to `true` to forbid JavaScript from accessing the cookie. See https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html#csrf-token-request-handler-breach for more details. #### Special notes for your reviewer: ```bash http http://localhost:8090/login -ph HTTP/1.1 200 OK set-cookie: XSRF-TOKEN=6d5dd83f-f0a7-4d94-a33e-73f213d679ff; Path=/; HTTPOnly ``` ```bash http http://localhost:8090/login -pb | grep _csrf ><input type="hidden" name="_csrf" value="ctubmrEC3dAbxC5H_k_-VnVUtih2BrfjcPfLmVAyaP0a1kAdEb-t_IcwuLM29B11yGLKNRQxm0lFZILOFZX-_GcHWJ974iR5"/> ``` #### Does this PR introduce a user-facing change? ```release-note None ```pull/6806/head
parent
845893944c
commit
5c50779693
|
@ -1,30 +1,29 @@
|
|||
package run.halo.app.security;
|
||||
|
||||
import static org.springframework.security.web.server.csrf.CookieServerCsrfTokenRepository.withHttpOnlyFalse;
|
||||
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.pathMatchers;
|
||||
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.web.server.csrf.CookieServerCsrfTokenRepository;
|
||||
import org.springframework.security.web.server.csrf.CsrfWebFilter;
|
||||
import org.springframework.security.web.server.csrf.ServerCsrfTokenRequestAttributeHandler;
|
||||
import org.springframework.security.web.server.csrf.XorServerCsrfTokenRequestAttributeHandler;
|
||||
import org.springframework.security.web.server.util.matcher.AndServerWebExchangeMatcher;
|
||||
import org.springframework.security.web.server.util.matcher.NegatedServerWebExchangeMatcher;
|
||||
import org.springframework.stereotype.Component;
|
||||
import run.halo.app.security.authentication.SecurityConfigurer;
|
||||
|
||||
@Component
|
||||
public class CsrfConfigurer implements SecurityConfigurer {
|
||||
class CsrfConfigurer implements SecurityConfigurer {
|
||||
|
||||
@Override
|
||||
public void configure(ServerHttpSecurity http) {
|
||||
var csrfMatcher = new AndServerWebExchangeMatcher(
|
||||
CsrfWebFilter.DEFAULT_CSRF_MATCHER,
|
||||
new NegatedServerWebExchangeMatcher(pathMatchers("/api/**", "/apis/**", "/system/setup")
|
||||
));
|
||||
new NegatedServerWebExchangeMatcher(
|
||||
pathMatchers("/api/**", "/apis/**", "/system/setup"))
|
||||
);
|
||||
http.csrf(csrfSpec -> csrfSpec
|
||||
.csrfTokenRepository(withHttpOnlyFalse())
|
||||
// TODO Use XorServerCsrfTokenRequestAttributeHandler instead when console implements
|
||||
// the algorithm
|
||||
.csrfTokenRequestHandler(new ServerCsrfTokenRequestAttributeHandler())
|
||||
.csrfTokenRepository(new CookieServerCsrfTokenRepository())
|
||||
.csrfTokenRequestHandler(new XorServerCsrfTokenRequestAttributeHandler())
|
||||
.requireCsrfProtectionMatcher(csrfMatcher));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package run.halo.app.infra.exception.handlers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.csrf;
|
||||
|
||||
import java.util.Locale;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -121,9 +122,8 @@ class I18nExceptionTest {
|
|||
|
||||
@Test
|
||||
void shouldGetConflictError() {
|
||||
webClient.put().uri("/response-entity/conflict-error")
|
||||
.header("X-XSRF-TOKEN", "fake-token")
|
||||
.cookie("XSRF-TOKEN", "fake-token")
|
||||
webClient.mutate().apply(csrf()).build()
|
||||
.put().uri("/response-entity/conflict-error")
|
||||
.exchange()
|
||||
.expectStatus().isEqualTo(HttpStatus.CONFLICT)
|
||||
.expectBody(ProblemDetail.class)
|
||||
|
|
Loading…
Reference in New Issue