본문 바로가기
코드 스테이츠

Spring Security - 보안

by 한휘용 2023. 7. 10.
728x90

Spring Security

Spring Security는 Java 기반의 애플리케이션에서 보안과 관련된 작업을 도와주는 프레임워크입니다.


Spring MVC 기반 애플리케이션의 인증(Authentication)과 인가(Authorization) 기능을 지원하는 보안 프레임워크로, 

Spring MVC 기반 애플리케이션에 보안을 적용하기 위한 다양한 기능을 적용합니다.

 

이러한 보안을 적용하기위해 Spring에서 지원하는 Interceptor나 Servlet Filter를 이용해서 보안 기능을 직접 구현할 수 있지만 웹 애플리케이션 보안을 대부분의 기능을 Spring Security에서 안정적으로 지원하고 있어 구조적으로 잘 만들고 검증된 Spring Security를 이용하는 것이 안전합니다.

Interceptor / Servlet Filter
Interceptor와 Servlet Filter는 웹 애플리케이션에서 요청을 가로채고 처리하는 기능을 제공합니다.

Interceptor는 웹 애플리케이션의 컨트롤러(Controller)에서 요청을 가로채고 처리하는 역할을 합니다.
Interceptor는 요청 전후에 추가 작업을 수행할 수 있으며, 주로 인증, 인가, 로깅, 예외 처리 등의 기능을 구현하는 데 사용됩니다. 

Servlet Filter는 Java Servlet API에서 제공되며, 웹 애플리케이션의 모든 요청을 가로채고 처리하는 역할을 합니다.
Filter는 요청과 응답의 전체 생명주기에 걸쳐 동작하며, URL 패턴에 따라 특정 요청을 필터링하고, 요청과 응답에 대한 작업을 수행할 수 있습니다. 주로 요청의 인코딩, 로깅, 인증, 캐시 제어 등의 작업을 처리하는 데 사용됩니다.

Interceptor / Servlet Filter 의 차이점
Interceptor는 주로 컨트롤러 내부에서 작동하며, 컨트롤러 메소드와 관련된 작업을 처리하는데 사용됩니다.
Servlet Filter는 웹 애플리케이션의 모든 요청에 대해 작동하며, 인코딩, 로깅, 인증, 캐시 제어 등의작업을 처리하는 데 사용됩니다.

 

 

Spring Security로 할 수 있는 보안 강화 기능

Spring Security를 애플리케이션에 적용하면 다음과 같은 일들을 할 수 있습니다.

 

1. 인증(Authentication)

사용자의 신원을 확인하여 인증하는 기능을 제공합니다.

사용자 이름과 비밀번호를 사용한 기본적인 인증뿐만 아니라 소셜 로그인, SSO(Single Sign-On) 등 다양한 인증 방식을 지원합니다.

 

2. 인가(Authorization)

인증된 사용자에 대한 권한을 관리하고 특정 리소스 또는 기능에 대한 접근 제어를 제공합니다.

롤(Role)이나 권한(Authority)을 기반으로 인가를 처리할 수 있습니다.

 

3. 암호화(Encryption)

사용자 비밀번호와 같은 중요한 데이터를 안전하게 저장하기 위한 암호화 기능을 제공합니다.

암호화된 비밀번호를 저장하고, 인증 시에 비밀번호를 비교하여 보안을 강화할 수 있습니다.

 

4. 세션 관리(Session Management)

세션을 관리하여 사용자의 로그인 상태를 유지하고, 세션 하이재킹(Session Hijacking)과 같은 공격으로부터 보호합니다. 세션 유효성 검사, 세션 타임아웃 설정 등을 통해 보안성을 강화할 수 있습니다.

 

5. CSRF(Cross-Site Request Forgery) 방지

CSRF 공격을 방지하기 위해 요청에 대한 유효성 검사를 수행합니다.

애플리케이션에서 생성된 토큰을 사용하여 요청의 출처를 확인하고, 유효하지 않은 요청을 거부합니다.

CSRF는 악의적인 공격자가 사용자의 권한을 이용하여 특정 웹 사이트에 요청을 보내는 공격입니다.

간단히 말하면, CSRF는 사용자의 의지와 무관하게 악성 요청을 전송하여 웹 애플리케이션의 보안을 침해하는 공격입니다.

 

 

6. 보안 헤더 추가

애플리케이션의 보안을 강화하기 위해 HTTP 응답 헤더에 보안 관련 헤더를 추가합니다.

 

7. 사용자 세부정보 관리

사용자의 세부정보를 저장하고 관리할 수 있는 기능을 제공합니다.

사용자 계정 정보를 안전하게 저장하고, 사용자 정보에 대한 접근과 수정을 제어할 수 있습니다.

 

 

Spring Security 용어 정리

Spring Security를 적용하기 위해서는 보안 영역에서 일반적으로 사용하는 개념들을 자주 접하게 됩니다.

이러한 보안 개념들을 사전에 이해하고 있다면 Spring Security의 기능을 조금 더 쉽게 이해하고 적용할 수 있습니다.

 

Spring Security에서 사용되는 보안 용어를 정리해 보겠습니다.

 

  • Principal(주체)
    • Spring Security에서 사용되는 Principal은 애플리케이션에서 작업을 수행할 수 있는 사용자, 디바이스 또는 시스템 등이 될 수 있으며, 일반적으로 인증 프로세스가 성공적으로 수행된 사용자의 계정 정보를 의미합니다.
  • Authentication(인증)
    • Authentication은 애플리케이션을 사용하는 사용자가 본인이 맞음을 증명하는 절차를 의미합니다.
    • Authentication을 정상적으로 수행하기 위해서는 사용자를 식별하기 위한 정보가 필요한데 이를 Credential(신원 증명 정보)이라고 합니다.
  • Authorization(인가 또는 권한 부여)
    • Authorization은 Authentication이 정상적으로 수행된 사용자에게 하나 이상의 권한(authority)을 부여하여 특정 애플리케이션의 특정 리소스에 접근할 수 있게 허가하는 과정을 의미합니다.
    • Authorization은 반드시 Authentication 과정 이후 수행되어야 하며 권한은 일반적으로 역할(Role) 형태로 부여됩니다.
  • Access Control(접근 제어)
    • Access Control은 사용자가 애플리케이션의 리소스에 접근하는 행위를 제어하는 것을 의미합니다.

 

 

Spring Security를 사용해야 하는 이유

 

 

Spring Security를 사용하지 않고 보안을 적용하려면 2가지 방법을 제시할 수 있습니다. 

 

1. 보안 프레임 워크를 사용하지 않고 직접 구현하여 적용하는 방법

2. Spring Security가 아닌 다른 보안 프레임워크를 사용하여 보안을 적용하는 방법

 

하지만 위에서 설명한 2가지 방법은 현실적으로 많이 어렵습니다.

 

1. 보안 프레임 워크를 사용하지 않고 직접 구현하여 적용하는 방법은 많은 어려움을 가집니다.

 

Spring Security를 사용해본 사람들이 항상하는 이야기는 '어렵다' 입니다.

Spring Security가 어렵게 느껴지는 가장 큰 이유는 보안이라는 주제 자체가 소프트웨어에서 어려운 주제 중 하나이기 때문입니다.

이미 만들어져서 가장 많이 사용되는 프레임워크를 사용하는 것도 어려운데 직접 보안 기능을 밑바닥부터 직접 구현하는 것보다 잘 검증되어 신뢰할 만한 Spring Security를 사용하는 것이 더 나은 선택입니다.

 

2. Spring Security가 아닌 다른 보안 프레임워크를 사용하여 보안을 적용하는 방법 또한 쉽지 않습니다.

애플리케이션의 보안을 강화하기 위한 솔루션으로 Spring Security 만 한 다른 프레임워크가 존재하지 않기 때문입니다.

 

물론 Apache Shiro, OACC 같은 보안 프레임워크가 존재는 하지만 Spring Security는 다른 보안 프레임워크가 제공하는 기능들을 모두 아우르는 기능을 지원하고 있으며, 또한 Spring 기반의 애플리케이션을 구현하는 개발자로서 Spring과 궁합이 가장 잘 맞는 Spring Security를 사용하는 것이 바람직합니다.

 

앞선 설명은 Spring Security가 아닌 다른 보안 방법의 사용이 어려운 이유에 대해 설명한 것입니다.

이제 Spring Security를 사용해야 하는 이유에 대해 설명 드리겠습니다.

 

1. 강력한 보안 기능

Spring Security는 인증, 인가, 암호화, 세션 관리, CSRF 방지 등 다양한 보안 기능을 제공합니다.

이를 통해 애플리케이션의 보안을 효과적으로 강화할 수 있습니다.

 

2. 편리한 구현과 통합

Spring Security는 Spring 프레임워크와의 원활한 통합을 지원합니다.

설정과 구현이 간단하며, 다른 Spring 기능과 함께 사용할 수 있어 개발 효율성을 높입니다.

 

3. 다양한 인증 방식 지원

Spring Security는 사용자 이름과 비밀번호를 사용한 인증뿐만 아니라 소셜 로그인, SSO(Single Sign-On) 등 다양한 인증 방식을 지원합니다.

 

4. 커스터마이즈 가능성

Spring Security는 유연한 구성 옵션을 제공하여 애플리케이션에 맞춤형 보안 요구사항을 충족할 수 있습니다.

필요한 경우 인증 및 인가 로직을 커스터마이즈하고, 접근 제어 규칙을 세밀하게 조정할 수 있습니다.

 

5. 업계 표준

Spring Security는 업계에서 폭넓게 사용되는 보안 프레임워크로 인정받고 있습니다.

신뢰성이 높고 커뮤니티 지원과 다양한 자료가 많아 개발에 도움이 됩니다.

 

Spring Security는 보안을 강화하고 사용자 데이터를 보호하는 데 필수적인 도구입니다.

안전한 애플리케이션을 구축하기 위해 Spring Security의 사용을 적극적으로 권장합니다.

 

Spring Security의 웹 요청 처리 흐름

Spring Security를 애플리케이션에 적용하는 데 어려움을 겪는 큰 이유 중의 하나는 Spring Security의 아키텍처와 Spring Security의 컴포넌트들이 어떻게 인터랙션 해서 인증, 권한 등의 보안 작업을 처리하는지 이해하지 못하기 때문입니다.

 

그리고 이러한 Spring Security의 동작 방식을 조금 더 잘 이해하기 위해서는 보호된 웹 요청을 처리하는 일반적인 처리 흐름과 Spring Security에서 지원하는 Filter의 역할을 이해하는 것이 선행되어야 합니다.

 

Spring Security의 웹 요청 처리 과정 중에서 가장 기본이 되는 웹 요청의 일반적인 흐름과 Spring Security에서 지원하는 Filter의 역할에 대해 살펴보겠습니다.

 

 

보안이 적용된 웹 요청의 일반적인 처리 흐름

Spring Security의 웹 요청 처리를 이해하기 위해서 알아두어야 할 부분은 먼저 보안이 적용된 웹 요청의 일반적인 흐름입니다.

보안이 적용된 웹 요청의 일반적인 처리 흐름

위 그림을 보면 보안이 적용된 사용자의 웹 요청에 대한 일반적인 처리는 다음과 같습니다.

 

 

1. 리소스 요청 

사용자가 보호된 리소스를 요청합니다. 

 

2. 크리덴셜 요청

인증 관리자 역할을 하는 컴포넌트에서 사용자의 신원을 확인하기 위해 사용자에게 크리덴셜을 요청합니다.

크리덴셜(Credential)은 사용자의 신원을 확인하기 위해 제공되는 정보입니다.
일반적으로 사용자가 자신을 인증하기 위해 제출하는 정보로, 사용자 이름과 비밀번호가 가장 일반적인 예시입니다.
보안 인증서와 지문,안면,홍채 패턴 인식 등과 같은 생체인식 데이터 또한 크리덴셜이 될 수 있습니다.

 

3. 크리덴셜 제공

사용자는 요청을 받아 인증 관리자에게 크리덴셜을 제공합니다.

 

4. 크리덴셜 조회

인증관리자는 크리덴셜 저장소에서 사용자의 크리덴셜을 조회합니다.

 

5. 크레덴셜 검증작업

인증 관리자는 사용자가 제공한 크리덴셜과 크리덴셜 저장소에 저장된 크리덴셜을 비교해 검증 작업을 수행합니다.

 

6. 크레덴셜 예외 확인

유효한 크리덴셜이 아니라면 Exception을 throw 합니다.

 

7 크레덴셜 검증 완료

유효한 크리덴셜이라면 접근 권한을 확인합니다.

 

8. 접근 권한 검증 작업

접근 결정 관리자 역할을 하는 컴포넌트는 사용자가 적절한 권한을 부여받았는지 검증합니다.

 

9. 접근 권한 예외 작업

적절한 권한을 부여받지 못한 사용자라면 Exception을 throw합니다.

 

10. 접근 권한 검증 완료

적절한 권한을 부여받은 사용자라면 보호된 리소스의 접근을 허용합니다.

 

 

웹 요청에서의 서블릿 필터와 필터 체인의 역할

서블릿 필터는 웹 애플리케이션에서 요청과 응답을 가로채고 처리하는 기능을 제공하는 컴포넌트입니다. 간단히 말하면, 필터는 웹 요청에 대한 전처리와 후처리 작업을 수행합니다.

 

이전 그림 예시에서 사용자의 웹 요청이 Controller 같은 엔드포인트를 거쳐 접근하려는 리소스에 도달하기 전에 인증 관리자나 접근 결정 관리자 같은 컴포넌트가 중간에 웹 요청을 가로채 사용자의 크리덴셜과 접근 권한을 검증하는 것을 볼 수 있었습니다.

 

이처럼 서블릿 기반 애플리케이션의 경우, 애플리케이션의 엔드포인트에 요청이 도달하기 전에 중간에서 요청을 가로챈 후 어떤 처리를 할 수 있는 적절한 포인트를 제공하는데 그것이 바로 서블릿 필터(Servlet Filter)입니다.

 

서블릿 필터는 하나 이상의 필터들을 연결해 필터 체인(Filter Chain)을 구성할 수 있습니다.

Servlet Filter Chain의 구성도

위 그림 예시에서 Spring Framework의 DispatcherServlet에 클라이언트의 요청이 전달되기 전에 필터 체인(Filter Chain)을 구성한 예입니다.

 

서블릿 필터는 각각의 필터들이 doFilter()라는 메서드를 구현해야 하며, doFilter() 메서드 호출을 통해 필터 체인을 형성하게 됩니다.

 

만약 Filter 인터페이스를 구현한 다수의 Filter 클래스를 예시와 같이 구현했다면 생성한 서블릿 필터에서 작성한 특별한 작업을 수행한 뒤, HttpServlet을 거쳐 DispatcherServlet에 요청이 전달되며, 반대로 DispatcherServlet에서 전달한 응답에 대해 역시 특별한 작업을 수행할 수 있습니다.

 

 

Spring Security에서의 필터 역할

서블릿 필터는 클라이언트의 요청 중간에 끼어들어 무언가 추가적인 작업을 할 수 있습니다.

 

그렇다면 Spring Security에서도 이 필터를 이용해 클라이언트의 요청을 중간에 가로챈 뒤, 추가로 보안 작업을 하는 거 아닐까? 라고 예상할 수 있습니다.

Servlet Filter Chain에 Spring Seucrity Filter 추가

위 그림 예시는 서블릿 필터에 Spring Security Filter가 추가된 예시입니다.

 

빨간 점선으로 이어진 박스 영역이 Spring Security Filter 영역입니다.

Spring Security Filter 영역안에 있는 필터의 이름이 서블릿 필터와는 다른 xxxxProxy로 이루어져 있습니다.

 

DelegatingFilterProxyFilterChainProxy 클래스는 Filter 인터페이스를 구현하기 때문에 서블릿 필터로써의 역할을 합니다.

 

 

- DelegatingFilterProxy

DelegatingFilterProxy는 스프링 프레임워크에서 제공하는 필터의 대리자 역할을 수행하는 클래스입니다.

스프링 빈으로 등록된 필터를 가져와서 필터링 작업을 수행합니다.

 

DelegatingFilterProxy라는 이름에서 알 수 있듯이 보안과 관련된 어떤 작업을 처리하는 것이 아니라 서블릿 컨테이너 영역의 필터와 ApplicationContext에 Bean으로 등록된 필터들을 연결해 주는 브리지 역할을 합니다.

 

간단하게 말하면, DelegatingFilterProxy는 서블릿 필터를 스프링 빈으로 등록하여 스프링 컨텍스트에서 필터를 관리하고 호출하는 역할을 합니다.

 

- FilterChainProxy

스프링 시큐리티에서 제공하는 필터 체인의 대리자 역할을 수행하는 클래스입니다.

스프링 시큐리티 필터 체인을 구성하고 관리하여 보안 기능을 구현합니다.

 

한마디로 FilterChainProxy부터 Spring Security에서 제공하는 보안 필터들이 필요한 작업을 수행한다고 생각하면 되겠습니다.

FilterChainProxy에 Spring Seucrity Filter Chain 추가

위 그림 예시는 갈 곳이 끊어진 FilterChainProxy에 Spring Security에서 지원하는 Filter Chain을 연결한 예시 입니다.

 

Spring Security의 Filter Chain은 URL 별로 여러 개 등록할 수 있으며, Filter Chain이 있을 때 어떤 Filter Chain을 사용할지는 FilterChainProxy가 결정하며, 가장 먼저 매칭된 Filter Chain을 실행합니다.

 

예를 들어

  • /api/** 패턴의 Filter Chain이 있고, /api/message URL 요청이 전송하는 경우
    • /api/** 패턴과 제일 먼저 매칭되므로, 디폴트 패턴인 /**도 일치하지만 가장 먼저 매칭되는 /api/** 패턴과 일치하는 Filter Chain만 실행합니다.
  • /message/** 패턴의 Filter Chain이 없는데 /message/ URL 요청을 전송하는 경우
    • 매칭되는 Filter Chain이 없으므로 디폴트 패턴인 /** 패턴의 Filter Chain을 실행합니다.

 

728x90