솔적솔적

SpringBoot기반으로 Security 개발(자세히 파해쳐보자)_3 본문

Back-end/Spring Boot Security

SpringBoot기반으로 Security 개발(자세히 파해쳐보자)_3

솔솔봄향기 2022. 2. 22. 00:57

✊ 학습목표

 1) 동시 세션 제어, 세션 고정 보호, 세션 정책

 2) 세션 제어 필터 - SessionManagementFilter, ConcurrentSessionFilter

 3) 권한설정과 표현식

 

1) 동시 세션 제어, 세션 고정 보호, 세션 정책

두 가지 전략으로

사용자1이 로그인하여 서버에 접속하면 세션 생성된 것임

사용자2가 동일한 계정으로 로그인한다. 세션2개 생성

서버에서 보안의 설정은 1개만이니 초과되었음

이럴 때 첫번째 전략은

이전 사용자의 세션 만료를 설정시키는 것이다.

첫번째 사용자1의 세션은 만료

사용자2껀 사용되게 되며 1개가 계속 이용할 수 있게 가능해지는 전략

두번째 전략

사용자1 서버 접속해 세션 생성,

사용자2 서버 접속 시 인증에 성공못하고 세션이 생성되지 못하도록 차단시키는 전략으로

최대 세션 허용 개수를 초과안하게 1개만 유지하게하는 것이다.

 

http.sessionManagement():세션 관리 기능이 작동함

protected void configure(HttpSecurity http) throws Exception{
	http.sessionMnagement()
		.maximumSessions(1)             //최대 허용 가능 세션 수, -1 : 무제한 로그인 세션 허용
		.maxSessionsPreventsLogin(ture) //동시 로그인 차단함, false: 기존 세션 만료(default)
		.invalidSessionUrl("/invalid")  //세션이 유효하지 않을 때 이동할 페이지
		.expiredUrl("/expired")         //세션이 만료된 경우 이동할 페이지
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Autowired
	UserDetailsService userDetailsService;

	protected void configure(HttpSecurity http, UserDetailsService userDetailsService) throws Exception {
		http
		.authorizeRequests()
		.anyRequest().authenticated();
		
		http
		.formLogin();
		
		http
			.sessionManagement()
			.maximumSessions(1)
			.maxSessionsPreventsLogin(true); //세션으 초과됐을 때 로그인을 아예 못하게하는 전략
	}
}

 

| 세션 고정 보호

사용자, 공격자, webApp가 있다고 치자

 

공격자 웹app에 접속하여 쿠키를 발급해주는 webapp,

이 때 공격자는 자신이 발급받은 쿠키를 사용자에게 심어놓고

사용자는 가지고 있게된다.

그럼 사용자는 공격자가 심어놓은 쿠키를 실행한다.

그러면 인증을받을 때 그 쿠키로 접근을 하고 그 쿠키에 해당하는 세션은 인증받은 상태이기 때문에

사용자나 공격자가 서버에 접근하게 되면 둘이 서버를 사용하게되는 일이 벌어지게된다.

공격자 쿠키 값으로 인증되어 버리기 때문에 공격자는 사용자 정보를 공유하게 된다는 것.

세션 고정 공격이다.

이걸 방지하기 위해 시큐리티는 세션고정보호의 기능을 제공한다.

사용자가 비록 공격자가 심어놓은 쿠키로 시도하더라도

인증할 때마다 새로운 세션이 생성되면

새로운 쿠키도 생성되어서 공격자는 사용자의 정보를 공유할 수 없다.

그럼 어떻게 제공이 되는 지 살펴보자

http.sessionManagement() : 세션 관리 기능이 작동함

protected void configure(HttpSecurity http) throws Exception{
		http.sessionManagement()
			.sessionRixation().changeSessionId() //기본값, non, migrateSession, new Session
    
	}

.sessionRixation().changeSessionId() → 기본값이면 세션아이디만 변경된다.

 

  • migrateSession : 새로운 세션발급, 세션고정보호
  • new Session : 새션에서 설정한 여러가지 속성의 값들을 사용못하고 새로 생성하는 것
  • none : 공격그대로 당하게 된다.

 

| 인증 API - 세션 정책

http.sessionManagement() : 세션 관리 기능이 작동함

protected void configure(HttpSecurity http) throws Exception{
	http.sessionManagement()
			.sessionCreationPolicy(SessionCreationPoliy.If_Required)
}

SessioncreationPolicy.Always : 스프링 시큐리티가 항상 세션 생성
SessionCreationPolicy.If_Required : 스프링 시큐리티가 필요시 생성(기본값)
SessionCreationPolicy.Never : 스프링 시큐리티가 생성하지 않지만 이미 존재하면 사용
SessionCreationPolicy.Stateless : 스프링 시큐리티가 생성하지 않고 존재해도 사용하지 않음

 

2) 세션 제어 필터 : SessionManagementFilter, ConcurrentSessionFilter

| 인증 API - SessionManagementFilter

  1. 세션 관리 - 인증 시 사용자의 세션 정보를 등록, 조회, 삭제 등의 세션 이력을 관리
  2. 동시적 세션 제어 - 동일 계정으로 접속이 허용되는 최대 세션수를 제한
  3. 세션 고정 보호 - 인증할 때마다 세션 쿠키를 새로 발급하여 공격자의 쿠키 조작을 방지
  4. 세션 생성 정책 - Always, If_Required, Never, Stateless

| 인증 API - concurrentSessionFilter

동시적 세션제어에 관여하는 ConcurrentSessionFilter

  • 매 요청 마다 현재 사용자의 세션 만료 여부 체크
  • 세션이 만료되었을 경우 즉시 만료 처리
  • Session.isExpired() == true
    • 로그아웃 처리
    • 즉시 오류 페이지 응답 “This session has been expired” 

3) 권한설정과 표현식

| 인가 API - 권한 설정

선언적 방식 과 동적인 방식이 있다.

  • 선언적 방식
    • URL
      • http.antMatchers(”/users/**”).hasRole(”USER”)
    • Method
      • @PreAuthorize(”hasRole(’USER’)”)
      • public void user() {System.out.println(”user”)}
  • 동적 방식 - DB 연동 프로그래밍
    • url
    • Method
  • authenticated() : 인증된 사용자의 접근을 허용
  • fullyAuthenticated() : 인증된 사용자의 접근을 허용, rememeber Me 인증 제외
  • permitAll() :무조건 겁근 허용
  • denyAll() : 무조건 접근을 허용하지 않음
  • anonymous() : 익명사용자의 접근을 허용
  • rememberMe() : 기억하기를 통해 인증된 사용자의 접근을 허용
  • access(String) : 주어진 SpEL표현식의 평가 결과가 true이면 접근을 허용
  • hasRole(String) 사용자가 주어진역할이 있다면 접근을 허용
  • hasAuthority(String) : 사용자가 주어진 권한이 있다면
  • hasAnyRole(String...) : 사용자가 주어진 권한이 있다면 접근을 허용
  • hasAnyAuthority(String...) : 사용자가 주어진 권한 중 어떤 것이라도 있다면 접근을 허용
  • haslpAddress(String) : 주어진 IP로부터 요청이 왔다면 접근을 허용
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().withUser("user").password("{noop}1111").roles("USER");
		auth.inMemoryAuthentication().withUser("sys").password("{noop}1111").roles("SYS", "USER");
		auth.inMemoryAuthentication().withUser("admin").password("{noop}1111").roles("ADMIN", "SYS", "USER");
		
	}
	
	protected void configure(HttpSecurity http) throws Exception{
		http
		.authorizeHttpRequests()
		.antMatchers("/user").hasRole("USER")
		.antMatchers("/admin/pay").hasRole("ADMIN")
		//.antMatchers("/admin/**").access("hasRole('ADMIN')or hasRole('SYS')")
		.anyRequest().authenticated();
		
		http
		.formLogin();
		}
	}

 

controller

package com.sole.security;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class securityController {

	@GetMapping("/")
	public String index() {
		return "home";
	}
	
	//@GetMapping("loginPage")
	//public String loginPage() {
	//	return "loginPage";
	//}
	
	@GetMapping("/user")
	public String user() {
		return "user";
	}
	
	@GetMapping("/admin/Pay")
	public String adminPay() {
		return "adminPay";
	}
	
	@GetMapping("/admin/**")
	public String admin() {
		return "admin";
	}
	
	
	
	
}

 

 

[참고 강의] 인프런 -  스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security