Tia*_*ite 11 spring-security spring-boot
我正在开发基于Spring Boot(spring-boot-starter-web)的REST API,其中使用Spring Security(spring-security-coree spring-security-config)保护不同的端点。
身份验证是通过使用本地数据库完成的,该本地数据库包含具有两个不同角色集的用户:ADMIN和USER。USER应该能够访问GET所有API端点以及POST基于的端点routeA。ADMIN应该能够与基于routeB的USERplus POST和DELETEend相同
但是,我得到的行为是,我可以GET向任何端点发出请求,但是对于任何类型的用户,POST请求总是返回HTTP 403 Forbidden- ADMIN和USER-这不是我期望的基于我的SecurityConfiguration。
关于我缺少什么的任何想法?
SecurityConfiguration.java
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private static final Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class);
@Autowired
private RESTAuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private DataSource dataSource;
@Override
public void configure(AuthenticationManagerBuilder builder) throws Exception {
logger.info("Using database as the authentication provider.");
builder.jdbcAuthentication().dataSource(dataSource).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().
authorizeRequests().antMatchers(HttpMethod.GET, "/**").hasAnyRole("ADMIN", "USER")
.antMatchers(HttpMethod.POST, "/routeA/*").hasAnyRole("ADMIN", "USER")
.antMatchers(HttpMethod.POST, "/routeB/*").hasRole("ADMIN")
.antMatchers(HttpMethod.DELETE, "/routeB/*").hasRole("ADMIN").and().
requestCache().requestCache(new NullRequestCache()).and().
httpBasic().authenticationEntryPoint(authenticationEntryPoint).and().
cors();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Run Code Online (Sandbox Code Playgroud)
RouteBController .java
@RestController
public class RouteBController {
static final Logger logger = LoggerFactory.getLogger(RouteBController.class);
public RouteBController() { }
@RequestMapping(value = "routeB", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET)
public String getStuff() {
return "Got a hello world!";
}
@RequestMapping(value = "routeB", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
public String postStuff() {
return "Posted a hello world!";
}
}
Run Code Online (Sandbox Code Playgroud)
RESTAuthenticationEntryPoint.java
@Component
public class RESTAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
@Override
public void afterPropertiesSet() throws Exception {
setRealmName("AppNameHere");
super.afterPropertiesSet();
}
}
Run Code Online (Sandbox Code Playgroud)
Tia*_*ite 15
有2个问题SecurityConfiguration.java使其无法正常运行。
尽管该403 Forbidden错误消息未包含任何指示其失败原因的消息(请参见下面的示例),但事实证明,这是由于启用了CSRF而导致的。禁用它允许POST和DELETE要求进行处理。
{
"timestamp": "2018-06-26T09:17:19.672+0000",
"status": 403,
"error": "Forbidden",
"message": "Forbidden",
"path": "/routeB"
}
Run Code Online (Sandbox Code Playgroud)
另外,antMatched(HttpMethod, String)for RouteB中使用的表达式也是错误的,因为/routeB/*期望它在after之后有一些东西/。正确的配置是/routeB/**因为可以存在(或不存在)更多路径。
该修正 SecurityConfiguration.java IS
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().
authorizeRequests().antMatchers(HttpMethod.GET, "/**").hasAnyRole("ADMIN", "USER")
.antMatchers(HttpMethod.POST, "/routeA/**").hasAnyRole("ADMIN", "USER")
.antMatchers(HttpMethod.POST, "/routeB/**").hasRole("ADMIN")
.antMatchers(HttpMethod.DELETE, "/routeB/**").hasRole("ADMIN").and().
requestCache().requestCache(new NullRequestCache()).and().
httpBasic().authenticationEntryPoint(authenticationEntryPoint).and().
cors().and().
csrf().disable();
}
Run Code Online (Sandbox Code Playgroud)
这是一个简单的 CSRF 启用问题,不允许 POST 请求。我遇到了同样的问题,这是解决方案:(解释)
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.POST,"/form").hasRole("ADMIN") // Specific api method request based on role.
.antMatchers("/home","/basic").permitAll() // permited urls to guest users(without login).
.anyRequest().authenticated()
.and()
.formLogin() // not specified form page to use default login page of spring security
.permitAll()
.and()
.logout().deleteCookies("JSESSIONID") // delete memory of browser after logout
.and()
.rememberMe().key("uniqueAndSecret"); // remember me check box enabled.
http.csrf().disable(); // ADD THIS CODE TO DISABLE CSRF IN PROJECT.**
}
Run Code Online (Sandbox Code Playgroud)
上面的代码:
Run Code Online (Sandbox Code Playgroud)http.csrf().disable();
将解决问题。
\n\n跨站点请求伪造是一种 Web 安全漏洞,攻击者可以利用该漏洞诱导用户执行他们不打算执行的操作。
\n
在您的情况下,禁用CSRF保护会使用户面临此漏洞。
\n\n\n注意:如果它是带有 O-Auth 保护的纯 Rest API,则不需要 CSRF。我应该在 Rest API 端点上使用 CSRF 保护吗?\n
\n
但是在您的情况下,当用户登录时创建会话并返回 cookie 作为响应,并且没有CSRF令牌 攻击者可以利用它并执行CSRF。
\n禁用 CSRF 不是一个好主意,相反,您可以将应用程序配置为在响应标头中返回 CSRF 令牌,然后在所有后续状态更改调用中使用它。
\n在您的SecurityConfiguration.java中添加这行代码
\n// CSRF tokens handling\nhttp.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class);\nRun Code Online (Sandbox Code Playgroud)\nCsrfTokenResponseHeaderBindingFilter.java
\npublic class CsrfTokenResponseHeaderBindingFilter extends OncePerRequestFilter {\n protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";\n protected static final String RESPONSE_HEADER_NAME = "X-CSRF-HEADER";\n protected static final String RESPONSE_PARAM_NAME = "X-CSRF-PARAM";\n protected static final String RESPONSE_TOKEN_NAME = "X-CSRF-TOKEN";\n\n @Override\n protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, javax.servlet.FilterChain filterChain) throws ServletException, IOException {\n CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);\n\n if (token != null) {\n response.setHeader(RESPONSE_HEADER_NAME, token.getHeaderName());\n response.setHeader(RESPONSE_PARAM_NAME, token.getParameterName());\n response.setHeader(RESPONSE_TOKEN_NAME, token.getToken());\n }\n\n filterChain.doFilter(request, response);\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n请注意,我们现在标头中有 CSRF 令牌。在会话过期之前,这不会改变。\n另请阅读:Spring Security\xe2\x80\x99s REST 服务的 CSRF 保护:客户端和服务器端,以便更好地理解。
\n| 归档时间: |
|
| 查看次数: |
5169 次 |
| 最近记录: |