๊ฐ์
ํ ์ดํ๋ก์ ํธ๋ฅผ ์งํํ๋ ๋์ค์ ์คํ๋ง ์ํ๋ฆฌํฐ๋ฅผ ์ค์ ํ๊ณ ๋์, ๋ก๊ทธ์ธ ์ธ์ฆ์ ๋ง์ณค๋๋ฐ๋ 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
๊ฐ์
ํ ์ดํ๋ก์ ํธ๋ฅผ ์งํํ๋ ๋์ค์ ์คํ๋ง ์ํ๋ฆฌํฐ๋ฅผ ์ค์ ํ๊ณ ๋์, ๋ก๊ทธ์ธ ์ธ์ฆ์ ๋ง์ณค๋๋ฐ๋ 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