programing

Spring Security는 SecurityConfig를 사용해도 POST 요구를 차단합니다.

javaba 2023. 2. 11. 17:33
반응형

Spring Security는 SecurityConfig를 사용해도 POST 요구를 차단합니다.

Spring Boot 기반의 REST API를 개발 중입니다.spring-boot-starter-webSpring Security를 사용하는 경우(spring-security-core e spring-security-config)를 사용하여 다른 엔드포인트를 보호합니다.

인증은 다음 두 가지 역할 세트를 가진 사용자를 포함하는 로컬 데이터베이스를 사용하여 수행됩니다.ADMIN그리고.USER.USER할 수 있을 것이다GET모든 API 엔드포인트 및POST기반으로 엔드포인트까지routeA.ADMIN같은 일을 할 수 있을 것이다USER플러스POST그리고.DELETE'routeB'에 기반한 엔드포인트

하지만 지금 내가 하고 있는 행동은GET모든 엔드포인트에 대한 요구는POST요청은 항상 반환됩니다.HTTP 403 Forbidden사용자 유형 중 하나에 대해 -ADMIN그리고.USER- 기대했던 것과는 다르게SecurityConfiguration.

내가 뭘 놓쳤는지 알아?


보안 설정자바

@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;
    }

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!";
    }

}

RESTAuthenticationEntryPoint.java

@Component
public class RESTAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {

    @Override
    public void afterPropertiesSet() throws Exception {
        setRealmName("AppNameHere");
        super.afterPropertiesSet();
    }
}

문제를 해결하기 위한 방법으로 CSFR을 비활성화하기 전에 Mohd Waseem의 답변에 기재된 리소스를 확인하여 그것이 왜 중요한지, 그리고 올바르게 셋업할 수 있는 방법을 파악하십시오.RCaetano가 말했듯이 CSFR은 공격으로부터 우리를 돕기 위해 여기에 있으므로 무작정 비활성화해서는 안 됩니다.

이 답변은 원래의 질문에 대한 2가지 문제를 설명했기 때문에 CSFT 및 보안 경로에서 발생할 수 있는 문제에 대한 인식을 높이기 위해 표시된 답변으로 남겨두지만 문자 그대로 받아들이지는 않습니다.


에서는 2개의 문제가 있었습니다.SecurityConfiguration.java잘못된 행동을 하게 만들었죠

단,403 Forbidden에러 메세지에는, 에러가 발생하고 있는 이유를 나타내는 메세지가 포함되어 있지 않습니다(아래의 예 참조).이것은 CSRF가 유효하게 되어 있기 때문입니다.다음 기간 동안 허용되는 비활성화POST그리고.DELETE처리되는 요청.

{
    "timestamp": "2018-06-26T09:17:19.672+0000",
    "status": 403,
    "error": "Forbidden",
    "message": "Forbidden",
    "path": "/routeB"
}

또, 에 사용되는 표현.antMatched(HttpMethod, String)위해서RouteB틀렸습니다./routeB/*그 뒤에 뭔가 있을 거라고 예상하다/올바른 설정은 다음과 같습니다./routeB/**더 많은 경로가 존재할 수 있기 때문에(또는 존재하지 않을 수도 있습니다.


수정한 SecurityConfiguration.java

@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();
}

출처: Stack Overflow em Portulués

사이트요청 위조는 공격자가 사용자가 의도하지 않은 작업을 수행하도록 유도할 수 있는 웹 보안 취약성입니다.

CSRF 보호를 디세블로 하면 사용자는 이 취약성에 노출됩니다.

주의: O-Auth 보호 기능이 있는 순수 Rest API일 경우 CSRF는 필요하지 않습니다.Rest API 엔드포인트에서 CSRF 보호를 사용해야 합니까?

단, 세션에 사용자 로그인이 생성되어 응답으로 cookie가 반환된 경우 공격자가 CSRF 토큰을 사용하지 않고 이를 부정 이용하는 경우 CSRF를 실행할 수 있습니다.

CSRF를 비활성화하는 것은 좋지 않습니다. 응답 헤더에 CSRF 토큰을 반환하도록 앱을 구성한 후 이후의 모든 상태 변경 호출에서 사용할 수 있습니다.

코드 행을 Security Configuration에 추가합니다.자바

// CSRF tokens handling
http.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class);

CsrfTokenResponseHeaderBindingFilter.java

public class CsrfTokenResponseHeaderBindingFilter extends OncePerRequestFilter {
    protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";
    protected static final String RESPONSE_HEADER_NAME = "X-CSRF-HEADER";
    protected static final String RESPONSE_PARAM_NAME = "X-CSRF-PARAM";
    protected static final String RESPONSE_TOKEN_NAME = "X-CSRF-TOKEN";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, javax.servlet.FilterChain filterChain) throws ServletException, IOException {
        CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);

        if (token != null) {
            response.setHeader(RESPONSE_HEADER_NAME, token.getHeaderName());
            response.setHeader(RESPONSE_PARAM_NAME, token.getParameterName());
            response.setHeader(RESPONSE_TOKEN_NAME, token.getToken());
        }

        filterChain.doFilter(request, response);
    }
}

헤더 응답 양식 서버:

이제 헤더에 CSRF 토큰이 있습니다.세션이 만료될 때까지 변경되지 않습니다., Spring Security의 REST 서비스에 대한 CSRF 보호(클라이언트측과 서버측)도 확인.

POST 요구를 허가하지 않는 단순한 CSRF 대응의 문제입니다.여기서도 같은 문제에 직면했습니다.(설명)

@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.**
}

위 코드:

http.csrf().disable();

문제가 해결됩니다.

언급URL : https://stackoverflow.com/questions/51026694/spring-security-blocks-post-requests-despite-securityconfig

반응형