πŸ’ Spring/Spring Security

[Spring Security] μŠ€ν”„λ§ μ‹œνλ¦¬ν‹° 403 Forbidden μ—λŸ¬

iseunghan 2021. 5. 13. 19:15
λ°˜μ‘ν˜•

κ°œμš”

ν† μ΄ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜λ˜ 도쀑에 μŠ€ν”„λ§ μ‹œνλ¦¬ν‹°λ₯Ό μ„€μ •ν•˜κ³  λ‚˜μ„œ, 둜그인 인증을 λ§ˆμ³€λŠ”λ°λ„ 403 Forbidden μ—λŸ¬κ°€ κ³„μ†ν•΄μ„œ λ°œμƒν•˜μ˜€μŠ΅λ‹ˆλ‹€. μ—λŸ¬κ°€ λ°œμƒν•˜λŠ” μ‹œμ μ΄ GET μš”μ²­μ€ 무리없이 잘 λ˜λŠ”λ°, POST μš”μ²­μœΌλ‘œ 보내면 μ΄μƒν•˜κ²Œ 403 μ—λŸ¬κ°€ λ‚˜λŠ”λ° 이유λ₯Ό λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€.

SecurityConfigλ₯Ό μ‚΄νŽ΄λ³΄μž

μ•„λž˜λŠ” κΈ°μ‘΄ μ‹œνλ¦¬ν‹° μ„€μ • μ½”λ“œμž…λ‹ˆλ‹€.

@Override
protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                    .antMatchers("/").authenticated()
                    .antMatchers("/user/**").permitAll()
                .and()
                    .formLogin()
                    .disable()
                .and()
                    .logout()
                    .logoutSuccessUrl("/")
                .and()
                    .oauth2Login()
                    .userInfoEndpoint()
                    .userService(customOAuth2UserService)
                .and()
                    .defaultSuccessUrl("/");
}

ν˜Ήμ‹œ λͺ°λΌμ„œ "/user/**"μš”μ²­μ„ permitAll() μ‹œμΌœμ€¬λŠ”λ°λ„ 계속 403 μ—λŸ¬κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.

μ•Œκ³  λ³΄λ‹ˆκΉŒ λ¬Έμ œλŠ” http.csrf().disable(); λ₯Ό 섀정해주지 μ•Šμ•„μ„œ

μŠ€ν”„λ§ μ‹œνλ¦¬ν‹°λ₯Ό μΆ”κ°€ν•˜λ©΄ 기본적으둜 csrf에 λŒ€ν•΄ μ²΄ν¬ν•˜κΈ° λ•Œλ¬Έμ— ν”„λ‘ νŠΈμ—μ„œ CSRF 토큰을 μ²˜λ¦¬ν•΄μ£Όμ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— POSTκ°€ μ •μƒμ μœΌλ‘œ μˆ˜ν–‰λ˜μ§€ μ•Šμ•˜λ˜ κ²ƒμž…λ‹ˆλ‹€.

μ•„λž˜μ²˜λŸΌ http.csrf() λ₯Ό disable() 해주도둝 ν•©μ‹œλ‹€!

@Override
protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                    .antMatchers("/").authenticated()
                    .antMatchers("/user/**").permitAll()
                .and()
                    .formLogin()
                    .disable()
                .and()
                    .logout()
                    .logoutSuccessUrl("/")
                .and()
                    .oauth2Login()
                    .userInfoEndpoint()
                    .userService(customOAuth2UserService)
                .and()
                    .defaultSuccessUrl("/");
}

 

μ™œ 이런 ν˜„μƒμ΄ λ°œμƒν–ˆμ„κΉŒ?

κ·Έ 전에 λ¨Όμ € CSRF에 λŒ€ν•΄μ„œ μ•Œμ•„μ•Ό ν•©λ‹ˆλ‹€. CSRF(Cross Site Request Forgery)λž€ μ‚¬μ΄νŠΈ κ°„ μš”μ²­ μœ„μ‘° 즉, μ‚¬μš©μžκ°€ μžμ‹ μ˜ μ˜μ§€μ™€ 상관없이 κ³΅κ²©μžκ°€ μ˜λ„ν•œ ν–‰μœ„(μˆ˜μ •, μ‚­μ œ, 생성)λ₯Ό νŠΉμ • μ‚¬μ΄νŠΈλ‘œ μš”μ²­ν•˜λ„λ‘ ν•˜λŠ” κ³΅κ²©μž…λ‹ˆλ‹€.

(μžμ„Έν•œ κ°œλ…κ³Ό 해결방법에 λŒ€ν•΄μ„œλŠ” 좔후에 ν¬μŠ€νŒ… ν•˜κ² μŠ΅λ‹ˆλ‹€)

μŠ€ν”„λ§ μ‹œνλ¦¬ν‹°μ—μ„œλŠ” csrf 토큰을 μ΄μš©ν•΄μ„œ λ°©μ–΄λ₯Ό ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 맀 μš”μ²­λ§ˆλ‹€ csrf 토큰은 μ„œλ²„μ—μ„œ μž„μ˜μ˜ λ‚œμˆ˜λ₯Ό μƒμ„±ν•˜μ—¬ ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ λ„˜κ²¨μ£ΌλŠ” κ²ƒμž…λ‹ˆλ‹€. 그럼 이제 ν΄λΌμ΄μ–ΈνŠΈλŠ” μ„œλ²„λ‘œ μš”μ²­ν•  λ•Œ λ°œκΈ‰λ°›μ€ csrf 토큰과 ν•¨κ»˜ μš”μ²­μ„ ν•˜λ©΄ μ„œλ²„μ—μ„œλŠ” csrf 토큰을 λΉ„κ΅ν•˜μ—¬ μœ„μ‘°λœ μš”μ²­μΈμ§€ νŒλ³„ν•˜κ²Œ λ˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

CSRFλ₯Ό 끄면 λ³΄μ•ˆμ— μ·¨μ•½ν•˜μ§€ μ•Šμ„κΉŒ

λ§Œμ•½ JWT와 같이 토큰 인증 방식을 μ‚¬μš©ν•œλ‹€λ©΄, μ„œλ²„μ— μƒνƒœκ°€ μ €μž₯λ˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— CSRF에 λŒ€ν•΄ λ³΄ν˜Έκ°€ ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ„Έμ…˜ μΏ ν‚€ λ°©μ‹μ˜ 인증방식을 μ‚¬μš©ν•œλ‹€λ©΄ κΌ­ CSRFλ₯Ό λŒ€λΉ„ν•΄μ•Ό ν•©λ‹ˆλ‹€. λΈŒλΌμš°μ €μ— μ €μž₯된 μΏ ν‚€κ°€ CSRF 곡격의 λ§€κ°œμ²΄κ°€ 되기 λ•Œλ¬Έμž…λ‹ˆλ‹€.

κ°μ‚¬ν•©λ‹ˆλ‹€.

μ°Έκ³ 

 

Cross Site Request Forgery (CSRF) :: Spring Security

When should you use CSRF protection? Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users. If you are creating a service that is used only by non-browser clients, you likely want to disable CSRF

docs.spring.io

 

Cross Site Request Forgery (CSRF) | OWASP Foundation

Cross Site Request Forgery (CSRF) on the main website for The OWASP Foundation. OWASP is a nonprofit foundation that works to improve the security of software.

owasp.org

 

λ°˜μ‘ν˜•