Spring 安全 CSRF 403 禁止成功登录
Spring Security CSRF 403 Forbidden on successful login
我在 index.html 和 login.html 的基本 Thymeleaf 设置上使用 Spring 安全性,但是默认登录页面总是 returns 403 Forbidden when the credentials有效的。 (如预期的那样,当凭据不匹配时会出现 UI 错误)。
我认为这是因为 CSRF 令牌已作为 cookie (XSRF-TOKEN) 包含在对后端的每个请求中。我不想简单地禁用 CSRF,所以我尝试以几乎所有我可以在网上找到的方式将此令牌包含到 POST 请求中:
- 将目标更改为
/login?_csrf=token
- 将
<input type="hidden" name="_csrf" ...
插入到 Thymeleaf 表单中(这是默认行为,我检查它确实发送了,但后端拒绝了??)
- 从普通表单提交切换到 AJAX/fetch 并插入 X-XSRF-TOKEN header。也不起作用,包括 JSON 和 x-www-form-urlencoded 编码请求。
有什么想法吗?请求中的默认 Spring 安全 /login
POST 端点期望什么?它如何期望 CSRF 令牌?
身份验证似乎有效,只是 CSRF 在成功登录时失败。还是完全是我遗漏的其他东西给了我 403 禁止?
提前致谢!!
我的设置
Spring启动版本:2.6.2
pom.xml 依赖项
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.zsoltfabok</groupId>
<artifactId>sqlite-dialect</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
index.html
<form th:action="@{/login}" method="post">
<label for="username">Username</label>
<input type="text" name="username" />
<label for="password">Password</label>
<input type="password" name="password" />
<button type="submit">Submit</button>
<!-- there's also a hidden CSRF token generated automatically -->
</form>
WebSecurityConfigurerAdapter
@Configuration
@EnableGlobalAuthentication
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// ...
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/favicon.ico").anonymous()
.antMatchers("/static/**").anonymous()
.mvcMatchers("/", "/login", "/signup").anonymous()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/")
.and()
.httpBasic()
.and()
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
WebMvcConfigurer
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
}
控制器
@Controller
@RequestMapping("/")
public class WebController {
@GetMapping
public String index() {
return "index";
}
}
问题出在您的安全规则上。
.antMatchers("/favicon.ico").anonymous()
.antMatchers("/static/**").anonymous()
.mvcMatchers("/", "/login", "/signup").anonymous()
您将它们配置为 匿名 访问。这意味着尚未通过身份验证的人。它将阻止经过身份验证的用户访问这些 URL 中的任何一个(如果您禁用了匿名访问,则可以防止未经身份验证的用户访问)。
修复允许使用 permitAll()
而不是 anonymous()
的任何人访问。
.antMatchers("/favicon.ico").permitAll()
.antMatchers("/static/**").permitAll()
.mvcMatchers("/", "/login", "/signup").permitAll()
我在 index.html 和 login.html 的基本 Thymeleaf 设置上使用 Spring 安全性,但是默认登录页面总是 returns 403 Forbidden when the credentials有效的。 (如预期的那样,当凭据不匹配时会出现 UI 错误)。
我认为这是因为 CSRF 令牌已作为 cookie (XSRF-TOKEN) 包含在对后端的每个请求中。我不想简单地禁用 CSRF,所以我尝试以几乎所有我可以在网上找到的方式将此令牌包含到 POST 请求中:
- 将目标更改为
/login?_csrf=token
- 将
<input type="hidden" name="_csrf" ...
插入到 Thymeleaf 表单中(这是默认行为,我检查它确实发送了,但后端拒绝了??) - 从普通表单提交切换到 AJAX/fetch 并插入 X-XSRF-TOKEN header。也不起作用,包括 JSON 和 x-www-form-urlencoded 编码请求。
有什么想法吗?请求中的默认 Spring 安全 /login
POST 端点期望什么?它如何期望 CSRF 令牌?
身份验证似乎有效,只是 CSRF 在成功登录时失败。还是完全是我遗漏的其他东西给了我 403 禁止?
提前致谢!!
我的设置
Spring启动版本:2.6.2
pom.xml 依赖项
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.zsoltfabok</groupId>
<artifactId>sqlite-dialect</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
index.html
<form th:action="@{/login}" method="post">
<label for="username">Username</label>
<input type="text" name="username" />
<label for="password">Password</label>
<input type="password" name="password" />
<button type="submit">Submit</button>
<!-- there's also a hidden CSRF token generated automatically -->
</form>
WebSecurityConfigurerAdapter
@Configuration
@EnableGlobalAuthentication
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// ...
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/favicon.ico").anonymous()
.antMatchers("/static/**").anonymous()
.mvcMatchers("/", "/login", "/signup").anonymous()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/")
.and()
.httpBasic()
.and()
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
WebMvcConfigurer
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
}
控制器
@Controller
@RequestMapping("/")
public class WebController {
@GetMapping
public String index() {
return "index";
}
}
问题出在您的安全规则上。
.antMatchers("/favicon.ico").anonymous()
.antMatchers("/static/**").anonymous()
.mvcMatchers("/", "/login", "/signup").anonymous()
您将它们配置为 匿名 访问。这意味着尚未通过身份验证的人。它将阻止经过身份验证的用户访问这些 URL 中的任何一个(如果您禁用了匿名访问,则可以防止未经身份验证的用户访问)。
修复允许使用 permitAll()
而不是 anonymous()
的任何人访问。
.antMatchers("/favicon.ico").permitAll()
.antMatchers("/static/**").permitAll()
.mvcMatchers("/", "/login", "/signup").permitAll()