2025-04-30
SecurityConfig
๊ตฌ์ฑ ์์ฝ@Configuration
@EnableWebSecurity // Spring Security ํ์ฑํ
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// CSRF ๋นํ์ฑํ (ํ
์คํธ์ฉ)
http.csrf().disable();
// ๊ถํ ๊ธฐ๋ฐ ์ ๊ทผ ์ค์
http.authorizeRequests()
.antMatchers("/", "/join").permitAll()
.antMatchers("/user").hasRole("USER")
.antMatchers("/manager").hasRole("MANAGER")
.antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated(); // ๊ธฐํ ์์ฒญ์ ์ธ์ฆ ํ์
// ๋ก๊ทธ์ธ/๋ก๊ทธ์์ ํ์ฉ
http.formLogin().permitAll();
http.logout().permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("{noop}1234").roles("USER")
.and()
.withUser("manager").password("{noop}1234").roles("MANAGER")
.and()
.withUser("admin").password("{noop}1234").roles("ADMIN");
}
}
๐ {noop}์ ๋น์ํธํ๋ ํ๋ฌธ ๋น๋ฐ๋ฒํธ ์ค์ ์ด๋ฏ๋ก, ์ค๋ฌด์์๋ ํด์ฑ ํ์์ ๋๋ค.
PasswordEncoder
Bean ๋ฑ๋ก ๋ฐ ์ฐ๋@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password(passwordEncoder.encode("1234")) // ํด์ฑ๋ ์ํธ ์ ์ฅ
.roles("USER");
}
์ ๋ ฅ ๋น๋ฐ๋ฒํธ | ๋ด๋ถ ์ ์ฅ๊ฐ |
---|---|
1234 | $2a$10$92Ex... (BCrypt ํด์) |
[๊ณต๊ฒฉ ์ฌ์ดํธ] โ (์ฌ์ฉ์ ํด๋ฆญ) โ [์ ์ ์ฌ์ดํธ ์์ฒญ ์ ์ก] โ ์๋ฒ๊ฐ ์ฌ์ฉ์ ์ธ์ฆ ์ ๋ณด๋ก ์ํ
<input type="hidden">
ํ๋ ์๋ ์ฝ์
<input name="_csrf" type="hidden" value="ํ ํฐ๊ฐ">
ํผ ์ ์ถ ์ ์๋์ผ๋ก ์๋ฒ๋ก ์ ์ก๋์ด ๊ฒ์ฆ๋จ
<form action="${pageContext.request.contextPath}/login" method="post">
USERNAME : <input name="username"/><br>
PASSWORD : <input name="password" type="password"/><br>
<input type="hidden" name="_csrf" value="${_csrf.token}"/>
<button>๋ก๊ทธ์ธ</button>
</form>
GET /logout์ CSRF ๋ณดํธ ํ์ฑํ ์ ์ฐจ๋จ๋จ โ POST ๋ฐฉ์ ์ฌ์ฉ ํ์
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
XSRF-TOKEN
์ด๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ธ๋ผ์ฐ์ ์ฟ ํค์ ์ ์ฅ๋จHttpOnly
๋นํ์ฑํ๋ก ์๋ฐ์คํฌ๋ฆฝํธ์์ ํ ํฐ ์ ๊ทผ ๊ฐ๋ฅ์ฟ ํค ์ด๋ฆ | ์ค๋ช |
---|---|
JSESSIONID | ์ธ์ ์๋ณ์ |
XSRF-TOKEN | CSRF ๋ณดํธ์ฉ ํ ํฐ |
๊ฐ๋ฐ์ ๋๊ตฌ์์ ํ์ธ ๊ฐ๋ฅ
fetch("/secure-api", {
method: "POST",
headers: {
"X-XSRF-TOKEN": getCookie("XSRF-TOKEN"),
"Content-Type": "application/json"
},
body: JSON.stringify({ ... })
});
getCookie๋ ์ฟ ํค์์ ํ ํฐ์ ๊บผ๋ด๋ ์ ํธ ํจ์ ํ์
X-XSRF-TOKEN
CookieCsrfTokenRepository
๋ก ์ฟ ํค ๊ธฐ๋ฐ ์ ์ก์ ํ์ฉํ๊ฑฐ๋, .disable()
์ค์ ์ ํตํด ์์ ๋นํ์ฑํ ๊ฐ๋ฅBCryptPasswordEncoder
์ ๊ฐ์ ํด์ฑ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํด์ผ ํ๋ฉฐ, {noop}
์ ํ์ต ๋ชฉ์ ์๋ง ์ฌ์ฉ