개발정리

스프링 시큐리티-CSRF 보호 본문

스프링/스프링 시큐리티

스프링 시큐리티-CSRF 보호

coffee. 2023. 9. 27. 15:36

CSRF란?

-CSRF공격은 웹 애플리케이션 취약점

-사용자의 의지와 무관하게 공격자가 의도한 행위를 웹사이트에 요청

 

CSRF의 조건

-사용자는 로그인 되어 있어야함

-사용자가 피싱 사이트 접속

 

CSRF 방어 기법

-Referrer 검증

-Security Token 사용

 

-일반적으로 CSRF공격 방어는 GET방식에는 방어 대상에 두지 않음

-스프링 시큐리티에서는 CsrfFilter가 보호 논리를 적용

-CsrfFilter는 CsrfTokenRepository를 사용해 CSRF토큰 관리

 

 

구현

@RestController
public class HelloController {

	@GetMapping("/hello")
	public String getHello() {
		return "Get Hello!";
	}
	
	@PostMapping("/hello")
	public String postHello() {
		return "Post Hello!";
	}
}
@Configuration
public class ProjectConfig {

	
	@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
       
       http.authorizeRequests()
       .anyRequest().permitAll();
            
        return http.build();
    }
}

 

현재 /hello 엔드포인트에 get 방식과 post방식이 정의 되어 있습니다.

포스트맨으로 확인해보면 get방식은 응답이 정상적으로 이루어지는 반면 post방식은 403에러가 발생합니다.

csrf토큰을 지정해주지 않았기 때문입니다.

 

<html> 

<head>

</head>


<body>
<h1>hello</h1>

<form action="/hello" method="post">
	<button type="submit">submit</button>
	<input type="hidden"
		th:name="${_csrf.parameterName}"
		th:value="${_csrf.token}"/>
</form>

</body>
</html>

 

 

로그인 시에 입장할 main 페이지를 만들어 줍니다.

 

@Configuration
public class ProjectConfig {

	@Bean
	public CsrfTokenRepository csrfTokenRepository() {
		return new HttpSessionCsrfTokenRepository();
	}
	
	@Bean
	public UserDetailsService uds() {
		var uds=new InMemoryUserDetailsManager();
		var u1 = User.withUsername("mary")
				.password("12345")
				.authorities("READ")
				.build();
		
		uds.createUser(u1);
		
		return uds;
	}
	
	@Bean
	public PasswordEncoder passwordEncoder() {
		return NoOpPasswordEncoder.getInstance();
	}
	
	
	
	@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
       
       http.authorizeRequests()
       .anyRequest().authenticated();
       
       http.formLogin()
       .defaultSuccessUrl("/main", true);
      
        return http.build();
    }
}
@Controller
public class MainController {

	
	@GetMapping("/main")
	public String main() {
		return "main";
	}
	
}

 

로그인시에  다음과 같은 페이지 가 띄어 집니다.

이 페이지에서 submit을 하게되면 /hello 엔드포인트를 post방식으로 보내게 됩니다.

이때 csrf토큰도 input에 의해 같이 보내지게되어 정상적으로 작동하게 됩니다.