Spring Security Architecture

김재현·2022년 8월 16일
0

Programmers

목록 보기
19/28

Conceptual Architecture

  • 거시적인 관점에서 Spring Security는 스프링 시큐리티는 결국 사용자의 인증과 관련된 처리를 담당함. 웹 요청을 가로챈 후 사용자를 인증하고, 인증된 사용자가 적절한 권한을 지니고 있는 확인.
    • AuthenticationManager 사용자 인증 관련 처리(인증 담당)
    • AccessDecisionManager 사용자가 보호받는 리소스에 접근할 수 있는 적절한 권한이 있는지 확인(인가 담당)

FilterChainProxy (Spring Security 필터 체인) 소개

  • Spring Security의 실제적인 구현은 서블릿 필터(javax.servlet.Filter 인터페이스 구현체) 를 통해 이루어짐
  • Spring Security는 결국 서블릿 필터를 구현하고 있는 필터 구현체들의 집합.
    • 서블릿 필터는 웹 요청을 가로챈 후 전처리 또는 후처리를 수행하거나, 요청 자체를 리다이렉트 하기도 함
    • Filter라는 것은 패키지 이름에서 알 수 있듯이 스프링이나 시큐리티에서 제공해주는 특수 인터페이스가 아니라, 자바에서 자체적으로 정의하고 있는 표준 인터페이스.
    • 스프링 시큐리티의 서블릿 필터 목록을 FilterChainProxy라고 부름.
  • FilterChainProxy 세부 내용은 WebSecurityConfigurerAdapter 추상 클래스를 상속하는 구현체에서 설정함 (보통 @EnableWebSecurity 어노테이션도 함께 사용)
    • 웹 요청은 이러한 필터 체인을 차례로 통과하게 됨
      • 웹 요청은 모든 필터를 통과하게 되지만, 모든 필터가 동작하는 것은 아님
      • 각 필터는 웹 요청에 따라 동작 여부를 결정할 수 있고, 동작할 필요가 없다면 다음 필터로 웹 요청을 즉시 넘김
    • 요청을 처리하고 응답을 반환하면 필터 체인 호출 스택은 모든 필터에 대해 역순으로 진행 (A > B > C 로 진행했다면, 반환시에는 C > B > A 순으로)
    • 보통 springSecurityFilterChain 이라는 이름으로 Bean 등록됨
  • 웹 요청은 어떻게 FilterChainProxy로 전달될까?
    • 웹 요청을 수신한 서블릿 컨테이너는 해당 요청을 DelegatingFilterProxy (javax.servlet.Filter 인터페이스 구현체) 로 전달함
    • DelegatingFilterProxy : 스프링 프레임워크에서 제공하며 스프링 시큐리티에서 한정적으로 동작하는 필터는 아님.
      • Delegate, 위임하기 위한 필터.
      • 필터에서 받은 웹 요청은 targetBeanName, 요청을 받을 타겟 빈을 지정. 타겟 빈에 해당하는 필터를 이니셜라이즈 하고, 들어온 요청을 딜리게이트로 전달함.
      • 요청을 받아 delegate로 전달하는 역할을 하는 프록시.
    • DelegatingFilterProxy Bean은 SecurityFilterAutoConfiguration 클래스에서 자동으로 등록됨
@Bean
@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(SecurityProperties securityProperties) {
	DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(DEFAULT_FILTER_NAME);
	registration.setOrder(securityProperties.getFilter().getOrder());
	registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
	return registration;
}

SecurityFilterAutoConfiguration 구현 발췌
(DelegatingFilterProxyRegistrationBean 을 통해 DelegatingFilterProxy 인스턴스를 생성함)

  • DelegatingFilterProxy는 실제적으로 웹 요청을 처리할 Target Filter Bean을 지정해야함
    • Target Filter Bean은 바로 앞에서 알아본 FilterChainProxy
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
	// Lazily initialize the delegate if necessary.
	Filter delegateToUse = this.delegate;
	if (delegateToUse == null) {
		synchronized (this.delegateMonitor) {
			delegateToUse = this.delegate;
			if (delegateToUse == null) {
				WebApplicationContext wac = findWebApplicationContext();
				if (wac == null) {
					throw new IllegalStateException("No WebApplicationContext found: " +
							"no ContextLoaderListener or DispatcherServlet registered?");
				}
				delegateToUse = initDelegate(wac);
			}
			this.delegate = delegateToUse;
		}
	}
	// Let the delegate perform the actual doFilter operation.
	invokeDelegate(delegateToUse, request, response, filterChain);
}

protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
	String targetBeanName = getTargetBeanName();
	Assert.state(targetBeanName != null, "No target bean name set");
	Filter delegate = wac.getBean(targetBeanName, Filter.class);
	if (isTargetFilterLifecycle()) {
		delegate.init(getFilterConfig());
	}
	return delegate;
}

protected void invokeDelegate(Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
		throws ServletException, IOException {
	delegate.doFilter(request, response, filterChain);
}

DelegatingFilterProxy 구현 발췌 (실제적으로 요청을 처리할 delegate 로 요청을 전달함)

  1. 서버를 생성하게 되면 FilterChain이 생성되나 이것은 Spring Security Filter Chain과 전혀 상관 없다.
    필터체인 목록에 Delegating Filter Proxy가 껴있음.
  2. 웹 요청이 필터체인을 통과하게 됨.
  3. 딜리게이팅 필터 프록시가 스프링 시큐리티 필터 체인을 가리키고 있고, 딜리게이팅 필터 프록시가 스프링 시큐리티 필터 체인 목록으로 웹 요청을 전달하게 되는 구조.

FilterChainProxy를 구성하는 Filter목록

  • 다양한 필터 구현을 제공.
  • 결국 Spring Security를 잘 이해하고 활용한다는 것은 이들 Filter 를 이해하고, 적절하게 사용한다는 것.
  • 주요 필터

  • 순서도 중요
    필터 체인에서 상대적인 순서에 맞게 작성된 표.

모든 필터 - 공식 사이트

인증 요청에 의해 가로채어진 원래 요청으로 이동하기 (RequestCacheAwareFilter)

  • 익명 사용자가 보호 받는 리소스 (예: /me)에 접근할 경우
    • 접근 권한이 없기 때문에 AccessDecisionManager 에서 접근 거부 예외가 발생
    • ExceptionTranslationFilter 접근 거부 예외를 처리함
      • 현재 사용자가 익명 사용자라면, 보호 받는 리소스로의 접근을 캐시처리하고, 로그인 페이지로 이동 시킴
      • 로그인이 완료되면 원래 접근하려 했던 페이지로 접근할 수 있게 한다. (예 : /me)
  • 정리하면, RequestCacheAwareFilter는 접근 거부를 발생시킨 원래의 페이지에 인증 이후 redirection 시키기 위해 존재하는 필터.
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
		throws IOException, ServletException {
	HttpServletRequest wrappedSavedRequest = this.requestCache.getMatchingRequest((HttpServletRequest) request,
			(HttpServletResponse) response);
	chain.doFilter((wrappedSavedRequest != null) ? wrappedSavedRequest : request, response);
}

RequestCacheAwareFilter 구현 일부 발췌

  • ExceptionTranslationFilter
  • FilterSecurityInterceptor : 인가 처리를 하는 AccessDecisionManager과 관련된 필터. 위의 로그인 하지 않은 상태에서 보호받는 리소스에 접근하려고 했을 때 접근거부가 일어나는 단계.

전송 레이어 보안 적용(ChannelProcessingFilter)

  • 채널 목록 가장 위에 위치하고 있음.
    웹 요청이 어떤 프로토콜로 (http 또는 https) 전달되어야 하는지 처리
  • 전송 레이어 보안을 위해 SSL 인증서를 생성하고, 이를 Spring Boot 웹 어플리케이션에 적용한다. 이제 웹 어플리케이션은 HTTPS 프로토콜을 통해 서비스 된다.

HTTP와 HTTPS

  • HTTP(Hyper Text Transfer Protocol)는 인터넷상에서 데이터를 주고 받기 위한 프로토콜
    • 클라이언트와 서버가 주고 받는 데이터는 암호화되어 있지 않음
    • 따라서, 악의적인 데이터 감청, 데이터 변조의 가능성이 있음
    • 웹 사이트에서 정보를 다룰 때 HTTP/HTTPS를 확인할 것. HTTP라면 민감 정보를 불특정 다수에게 알려주는 것과 다름 없다.
  • HTTPS(HyperT ext Transfer Protocol Secure)는 HTTP 프로토콜의 암호화 버전
    • 클라이언트와 서버가 주고 받는 모든 데이터는 암호화되어 있음
    • 데이터 암호화를 위해 SSL(Secure Sockets Layer)을 사용
      👍 SSL은 Netscape가 개발했으며 SSL 3.0부터 TLS라는 이름으로 변경되었다. 일반적으로 SSL, TLS은 같은 의미를 지닌다. 그러나 SSL이란 용어가 더 많이 사용된다.
  • SSL 암호화를 위해 SSL 인증서가 필요함
    • 서버는 SSL인증서를 클라이언트에 전달함
    • 클라이언트는 서버가 전달한 SSL 인증서를 검증하고, 신뢰할 수 있는 서버인지 확인함
    • 신뢰할 수 있는 서버라면 SSL 인증서의 공개키를 이용해 실제 데이터 암호화에 사용될 암호화키를 암호화하여 서버에 전달함
      • 실제 데이터 암복호화는 대칭키 방식
      • 서버와 클라이언트 사이의 대칭키 공유를 위해 RSA 암호화를 사용함
  • 공개키 : 누구든지 키를 확인할 수 있고 사용할 수 있도록 대중에게 공개된 키.
    ↔ 개인키 : 자신만이 관리하고 사용할 수 있는 키.

대칭키

  • 대칭키 암호화
    : 어떤 정보를 암호화, 복호화 할 때 사용하는 키가 동일(대칭)한 경우. 즉, 암호화를 할 때 필요한 키값과 해당 정보를 복호화 할 때 필요한 키값이 동일한 경우.
    • 어떤 정보가 대칭키를 통해 암호화되었다면, 똑같은 키를 갖고 있는 사용자가 아니면 해당 정보를 확인할 수 없음.
    • 이러한 키를 안전하게 교환하는 것이 대칭키 암호화 방식의 가장 중요한 부분이라 할 수 있다.
  • 비대칭키 암호화
    : 어떤 정보를 암호화, 복호화 할 때 사용하는 키가 서로 다른 경우.
    대칭키와 다르게 비대칭키를 사용한 암호화에는 개인키와 공개키 두 가지가 사용되며, 비대칭키를 활용한 암호화는 개인키로 암호화를 하는 방식 / 공개키로 암호화를 하는 방식 두 가지로 나뉘게 된다.
  • 1) 공개키로 암호화
    • 어떤 정보를 특정 사용자에게 보낼 때 해당 사용자의 공개키를 통해 정보를 암호화하여 전송.
    • A가 B에게 정보를 전송할 때 B의 공개키를 이용해 정보를 암호화 해서 보낸다. > 정보는 B의 공개키로 암호화되었기 때문에 열람을 위해서는 B의 개인키가 필요하다. (공개키로 암호화 되었다면 개인키로 해제 가능. 공개키로 해제는 불가능.)
    • 대칭키의 키값 교환에 따른 문제를 해결한 방법이라 할 수 있다.
  • 2) 개인키로 암호화
    • 개인키는 자신만이 가지고 있는 키이므로, 어떠한 정보를 특정 사용자에게 보낼 때 자기자신의 개인키를 통해 정보를 암호화해서 전송.
    • A가 B에게 정보를 보낼 때 A의 개인키를 통해 정보를 암호화해서 B에게 보냄. 이 정보는 A의 개인키로 암호화되었기 때문에 A의 공개키를 알아야 정보의 열람이 가능하고 A의 공개키는 누구나 알 수 있도록 공개되어 있기에 B는 A의 공개키를 통해 정보의 열람이 가능.
    • A의 공개키가 공개되어 있다면, 누구나 열어볼 수 있으니 보안에 취약한 것이 아닌가? > 취약한 것이 맞다. 때문에 이 방법은 '정보가 무엇인가.' 보다 '정보를 누가 보냈는가?'에 초점을 둔 방식.
    • 이 기술은 데이터 제공자의 신원이 보장되는 '전자서명'등 공인인증체계의 기본이 된다.

암호화

  • 전송, 수신, 저장하는 정보를 해독할 수 없도록 비밀 코드로 변환하는 기술적 프로세스. 기본적으로 알고리즘을 이용해 데이터를 변환하며, 이렇게 변환된 데이터를 수신하는 측은 해독 키를 사용해 데이터를 해독한다.
    암호화되지 않은 파일에 포함된 변환되지 않은 메시지는 '평문'으로 불리고, 암호화된 형식의 메시지는 '암호문'이라 부른다.
  • 웹사이트에 송수신되는 데이터를 암호화하는 보안 소켓 계층(SSL)
  • 전송 계층 보안(TSL)

SSL 인증키

RSA 암호화

  • 공개키 암호시스템의 하나로, 암호화뿐만 아니라 전자서명이 가능한 최초의 알고리즘(으로 알려져있음).
  • 큰 숫자를 소인수 분해하는 것이 어렵다는 것에 기반을 두고 있음. 양자컴퓨터로 임의 정수를 빠르게 소인수 분해하는 법이 나왔기에, 양자컴퓨터가 본격적으로 실용화되면 RSA알고리즘은 무용지물이 될 가능성이 있다.
  • 두 개의 키를 사용한다. 여기서 키란 메시지를 열고 잠그는 상수(constant)를 의미. 일반적으로 많은 공개키(public key) 알고리즘의 공개키는 모두에게 알려져 있으며 메시지를 암호화(encrypt)하는데 쓰이며, 암호화된 메시지는 개인키를 가진 자만이 복호하(decrypt)하여 열어볼 수 있다.
  • 공개키 알고리즘은 누구나 어떤 메시지를 암호화할 수 있지만, 그것을 해독하여 열람할 수 있는 사람은 개인키를 지닌 단 한 사람만이 존재한다는 점에서 대칭키 알고리즘과 차이를 갖는다.

SSL 인증서 생성

  • keytool 도구를 이용해 임의로 SSL 인증서를 생성할 수 있음
    keytool은 Java 설치 경로 bin 디렉토리 아래에 위치.
    • 물론 실제 서비스에는 사용할 수 없으며, 어디까지나 로컬 테스트 용도로만 활용해야 함
  • keystore 만들기
    • keytool -genkey -alias [keystore 별칭] -keyalg RSA -storetype PKCS12 -keystore [keystore 파일]
  • keystore 에서 인증서 추출하기
    • keytool -export -alias [keystore 별칭] -keystore [keystore 파일] -rfc -file [인증서 파일]
  • trust-store 만들기
    • keytool -import -alias [trust keystore 별칭] -file [인증서 파일] -keystore [trust keystore 파일]

SSL 인증서 적용

  • prgrms_keystore.p12, prgrms_truststore.p12 2개 파일을 resources 디렉토리로 복사 후 application.xml 파일에 설정 추가
    • 포트를 443으로 변경 (HTTPS 기본 포트)
    • server.ssl 설정 추가
  spring:
  application:
    name: spring security 01
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
  thymeleaf:
    cache: true
  security:
    user:
      name: user
      password: user123
      roles: USER
  messages:
    basename: i18n/messages
    encoding: UTF-8
    cache-duration: PT1H
server:
  port: 443
  ssl:
    enabled: true
    key-alias: prgrms_keystore
    key-store: classpath:prgrms_keystore.p12
    key-store-password: prgrms123
    key-password: prgrms123
    trust-store: classpath:prgrms_truststore.p12
    trust-store-password: prgrms123
  • 웹 어플리케이션을 시작하면 443 (https) 포트를 통해 서비스가 기동하는 것을 로그로 확인할 수 있음

Spring Security 설정하기

  • ChannelProcessingFilter 설정을 통해 HTTPS 채널을 통해 처리해야 하는 웹 요청을 정의할 수 있음
    • FilterInvocationSecurityMetadataSource 클래스에 HTTPS 프로토콜로 처리해야 URL 정보가 담김
    • 실제적인 처리를 ChannelDecisionManager 클래스로 위임함
    • HttpSecurity 클래스를 통해 ChannelProcessingFilter 세부 설정을 할 수 있음

0개의 댓글