728x90

SecurityContextHolder

 

 

스프링 시큐리티 인증 모델의 핵심으로 SecurityContext를 포함한다.

 

Holder라는 단어의 의미를 생각해 보면 이해하기 쉬운데

여기서 Holder는 소유자, 보유자 같은 의미로

SecurityContext를 가지고 있는 존재라는 것이다.

 

위의 사진을 보면 SecurityContext는 인증과 관련된 정보들을 가지고 있는데

즉, SecurityContextHolder는 이러한 SecurityContext들을 저장하는 공간이다.

//SecurityContextHolder에 저장할 SecurityContext를 하나 생성
SecurityContext context = SecurityContextHolder.createEmptyContext(); 

//SecurityContext에 저장할 인증정보 생성
Authentication authentication =
    new TestingAuthenticationToken("username", "password", "ROLE_USER"); 

//SecurityContext에 생성한 인증정보 할당
context.setAuthentication(authentication);

//SecurityContext를 SecurityContextHolder에 저장
SecurityContextHolder.setContext(context);

SecurityContextHolder에 SecurityContext를 저장하는 간단한 코드다.

 

결국 인증에 대한 모든 정보들은 SecurityContextHolder가 가지고 있기 때문에

이를 얻기 위해서는 SecurityContextHolder에 접근해야 한다.

//SecurityContextHolder에서 SecurityContext 가져오기
SecurityContext context = SecurityContextHolder.getContext();

//SecurityContext에서 인증정보 가져오기
Authentication authentication = context.getAuthentication();

//인증정보에서 필요한 정보들 가져오기
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

SecurityContextHolder >> SecurityContext >> Authentication

위와 같은 순서로 인증정보에 접근할 수 있다.

 

SecurityContextHolder는 ThreadLocal을 사용해 인증에 대한 상세정보들을 저장하는데

이해하기 쉽게 설명하자면 동일한 스레드의 메서드에서는 SecurityContext룰 언제든 사용할 수 있다.

public void testMethod(파라미터로 SecurityContextHolder를 받지 않아도) {
	//아래의 과정들을 그대로 수행할 수 있음
	//SecurityContextHolder에서 SecurityContext 가져오기
	//SecurityContext에서 인증정보 가져오기
	//인증정보에서 필요한 정보들 가져오기
}

SecurityContext를 메서드의 파라미터 같은 것으로 전달받지 않아도

현재 스레드의 어떤 메서드에서든 SecurityContextHolder를 통해

SecurityContext에 접근할 수 있다는 것이다.

 

SecurityContext

위에서 살펴봤던 것처럼 인증정보를 감싸고 있는 객체로

SecurityContextHolder에 포함된다.

Authentication

Authentication은 스프링 시큐리티에서 두 가지 목적을 가지고 사용할 수 있다.

 

첫 번째로는 인증을 위한 크레덴셜을 제공하기 위한 AuthenticationManager에 대한 입력으로

이 경우에는 isAuthenticated()의 리턴값은 false다.

 

두 번째로는 현재 인증된 사용자를 나타내기 위한 경우로

위에서 살펴본 SecurityContext로부터 인증정보를 얻을 때 사용된다.

 

정리하자면 인증을 위한 크레덴셜 제공과

이미 인증된 사용자의 정보를 얻기 위한 목적을 가지고 있다.

 

다음의 3가지를 포함한다.

  • Principal : 보안주체로 사용자를 식별할 때 사용된다.
  • Credentials : 인증에 필요한 수단으로 보통 패스워드를 의미한다.
  • Authorities : GrantedAuthority 객체로 사용자가 어디까지 접근할 수 있는지에 대한 권한이다.(역할 및 범위)

GrantedAuthority

인증된 사용자가 어떤 요청까지 가능한지에 대한 권한을 부여하는 객체로

역할 기반과 범위 기반 방식이 있다.

 

예를 들면, 로그인한 사용자의 역할이 일반 사용자인지 관리자인지에 따라

어떤 페이지에(요청) 접근할 수 있는지 통제할 수 있다.

AuthenticationManager

스프링 시큐리티 필터가 인증을 어떻게 수행하는지 정의하는 API로

실질적인 인증을 직접 처리하는 것이 아니라

인증 과정들을 순서대로 진행하도록 조율한다.

 

AuthenticationManager를 통해 최종적으로 반환된 Authentication은

AuthenticationManager를 호출한 컨트롤러(사실상 스프링 시큐리티의 필터)에 의해 

SecurityContext에 감싸져 SecurityContextHolder에 저장된다.

 

SecurityContextHolder에 대해서 살펴볼 때 봤던 코드처럼

직접 지정하거나 AuthenticationManager를 사용하지 않는 방법도 있다.

 

일반적으로 AuthenticationManager의 구현 클래스는 ProviderManager다.

ProviderManager

 

 

ProviderManager는 인증의 수행을 AuthenticationProvider의 인스턴스 목록에 위임하는데

각각의 AuthenticationProvider는 인증의 성공, 실패에 대해 결정하거나

결정할 수 없는 경우 다음 AuthenticationProvider가 결정할 수 있도록 한다.

 

즉, 각각의 AuthenticationProvider는 특정 인증 방식에 대한 인증을 수행하는데

예를 들어 첫번째 AuthenticationProvider는 Username/Password 방식을 수행하면

다른 하나는 SAML 방식의 인증을 수행한다.

 

간단하게 설명하자면 하나의 ProviderManager를 통해

여러 인증 방식(AuthenticationProvider)을 사용할 수 있다.

AuthenticationProvider

여러 인증 방식(AuthenticationProvider)을 ProviderManager에 주입할 수 있다.

 

위에서도 언급했듯이 각각의 AuthenticationProvider는 특정 인증을 수행하는데

예를 들면 DaoAuthenticationProvider를 주입하면 유저네임/패스워드 기반의 인증을,

JwtAuthenticationProvider를 주입하면 JWT 토큰 방식의 인증도 수행할 수 있다.

Request Credentials with AuthenticationEntryPoint

클라이언트에게 자격증명을 요청하는 HTTP 응답을 처리할 때 사용된다.

 

쉽게 말하자면 인증되지 않은 요청에 대해 클라이언트에게 다시 인증을 요구하는 것으로

로그인하지 않은 사용자가 마이 페이지에 접속하는 경우에

로그인 페이지로 리다이렉트 하는 경우에 사용된다고 이해하면 된다.

AbstractAuthenticationProcessingFilter

사용자의 크레덴셜을 인증하기 위한 기본 필터로

크레덴셜이 인증되기 전에 스프링 시큐리티는 일반적으로

AuthenticationEntryPoint를 사용해 크레덴셜을 요청한다.

 

그 후에 AbstractAuthenticationProcessingFilter가

제출된 모든 인증 요청에 대해 인증할 수 있다.

 

 

 

간단하게 순서를 살펴보자면 아래와 같다.

  1. 사용자가 자신의 크레덴셜을 제공
  2. AbstractAuthenticationProcessingFilter가 인증할 Authentication을 생성 (아직 인증되지 않은 상태)
  3. 생성된 Authentication이 AuthenticationManager에 전달
  4. 인증에 실패하면 SecurityContextHolder를 비우고 실패에 대한 작업을 진행
  5. 인증에 성공하면 SecurityContextHolder에 Authentication을 저장하는 등 성공에 대한 작업 진행
728x90

의존성 추가

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-security'
}

gradle 파일에 위의 스프링 시큐리티 의존성을 추가한 후에

별다른 설정 없이 서버를 실행한 후에 로컬 환경에서 사이트에 접속해보겠다.

 

 

접속해보면 로그인 페이지나 기능을 구현한 적이 없어도

스프링 시큐리티에서 기본적으로 제공해주는 인증 페이지로 접속되는걸 확인할 수 있다.

 

 

 

기본 인증은 Username에 user, Password에 위의 비밀번호를 복사해서 로그인 할 수 있다.

 

인증을 하기 전까지는 어떤 요청을 보내더라도 위의 페이지가 뜨게 되고

인증된 후에야 응답을 받을 수 있게 된다.

 

 

시큐리티의 기본적인 인증 방식은 위의 사진에서 알 수 있듯이

세션을 사용하여 인증 정보를 관리한다.

@EnableWebSecurity 
@Configuration
public class DefaultSecurityConfig {
    @Bean
    @ConditionalOnMissingBean(UserDetailsService.class)
    InMemoryUserDetailsManager inMemoryUserDetailsManager() { 
        String generatedPassword = // 랜덤 패스워드 생성;
        return new InMemoryUserDetailsManager(User.withUsername("user")
                .password(generatedPassword).roles("ROLE_USER").build());
    }

    @Bean
    @ConditionalOnMissingBean(AuthenticationEventPublisher.class)
    DefaultAuthenticationEventPublisher defaultAuthenticationEventPublisher(ApplicationEventPublisher delegate) { 
        return new DefaultAuthenticationEventPublisher(delegate);
    }
}

위의 코드는 스프링 시큐리티의 기본 설정값이다.

 

서버를 처음 실행할 때마다 랜덤으로 패스워드를 설정하여

Username은 user고 Password는 랜덤 패스워드, 역할은 ROLE_USER인 인증 정보를 생성한다.

 

이런 과정을 통해서 의존성을 추가한 것만으로도 기본 로그인 기능을 사용할 수 있었다.

 

728x90

OAuth 2.0 인증 컴포넌트

 

Resource Owner

사용하고자 하는 리소스의 주인으로 웹 애플리케이션의 실제 사용자라고 생각하면 편하다.

 

구글 로그인 인증을 통해 사용자가 자신의 구글 계정으로

자신의 리소스를 사용하는 것이기 때문에 Resource Owner라고 부른다.

 

Client

써드 파티 애플리케이션을 사용하지 않는 기존의 웹 애플리케이션에서

클라이언트는 사용자에 해당했지만

OAuth 2.0에서의 클라이언트는 웹 애플리케이션에 해당한다.

 

클라이언트는 서비스를 이용하는 쪽이고 서버는 제공하는 쪽인데

써드 파티 애플리케이션의 서비스를 제공받는 쪽은

웹 애플리케이션에 해당하기 때문이다.

 

Resource Server

클라이언트의 요청을 수락하고 Resource Owner의 Resource를 제공하는 서버로

써드 파티 애플리케이션의 서비스를 제공하는 쪽이 여기에 해당한다고 생각하면 된다.

 

Authorization Server

클라이언트가 Resource Server에 접근할 수 있는 권한을 부여하는 서버로

인증에 성공한 클라이언트에 Resource 접근 권한이 있는 액세스 토큰을 부여한다.

 

인증 처리 흐름

  1. Resource Owner의 인증 요청
  2. 웹 애플리케이션 서버가 써드 파티 로그인 페이지로 Redirect
  3. Authorization Server가 Resource 접근 권한이 있는 액세스 토큰 생성 후 전달
  4. 웹 애플리케이션 서버가 액세스 토큰으로 Resource Server에 요청
  5. Resource Server가 Resource Owner의 Resource 전달

 

용어

Authorization Grant

클라이언트가 액세스 토큰을 얻기 위한 수단을

Resource Owner의 권한을 표현하는 크리덴셜이다.

 

아래와 같이 4가지 타입이 있다.

  1. Authorization Code
    • 자체 생성한 Authorization Code를 전달하여 권한 부여 승인을 하는 방식
    • 가장 많이 쓰이는 방식
    • Refresh Token 사용 가능
    • 권한 부여 승인 요청 시 응답 타입을 code로 지정하여 요청
  2. Implicit Grant Type
    • Authorization Code 없이 바로 액세스 토큰을 발급하는 방식
    • 자격증명을 안전하게 저장하기 힘든 클라이언트에서 사용
    • Refresh Token 사용 불가능
    • 권한 부여 승인 요청 시 응답 타입을 token으로 지정하여 요청
  3. Client Credentials
    • 클라이언트가 관리하는 리소스에 접근할 때 사용
    • Authorization Server에 클라이언트에 제한된 리소스 접근 권한이 설정된 경우 사용
    • 자격 증명을 안전하게 보관할 수 있는 클라이언트에서만 사용해야 함
    • Refresh Token 사용 불가능
  4. Resource Owner Password Credentials
    • 로그인 시 필요한 정보로 액세스 토큰을 발급받는 방식
    • 같은 서비스에서 제공하는 애플리케이션의 경우에만 사용
    • 네이버 계정으로 로그인 하여 네이버의 웹툰, 카페, 블로그 등을 이용하는 경우가 해당
    • 즉 권한 부여 서버, 리소스 서버, 클라이언트가 모두 같은 시스템이여야 함
    • Refresh Token 사용 가능

 

Access Token

클라이언트가 리소스 서버의 보호된 리소스에 액세스 하기 위해 사용하는 자격증명용 토큰

 

Scope

주어진 액세스 토큰을 사용할 수 있는 범위로

액세스할 수 있는 리소스의 범위다.

728x90

OAuth 2.0

애플리케이션에서 사용자의 인증을 직접 처리하지 않고

신뢰할 수 있는 써드 파티 애플리케이션이 대신 처리하게 한 후에

해당 써드 파티 애플리케이션의 서비스까지 사용할 수 있는 방식이다.

 

간단하게 말하자면 요새 자주 사용되는

구글/카카오/네이버 등을 이용한 로그인 방식이다.

 

기존 서버에서 인증을 하고 외부 애플리케이션의 서비스를 이용하려면

외부 애플리케이션에서도 인증을 받아야 해서

두 번의 인증 과정이 필요하지만

이 방식을 사용하면 한 번의 인증만으로도 가능해진다.

 

인증 방식

OAuth 2.0를 사용하지 않는 기존의 로그인 방식은

클라이언트 요청 → 웹 서버 인증 → 외부 애플리케이션 서버 인증 순서로 진행되었다면

OAuth 2.0를 사용하게 되면

클라이언트 요청 → 웹 서버가 써드 파티 애플리케이션이 인증 위임 순서로 진행된다.

 

자세하게 적어보자면 아래와 같다.

  1. 클라이언트의 인증 요청
  2. 웹 서버가 써드 파티 애플리케이션에 인증 위임
  3. 써드 파티 애플리케이션이 인증 처리 후 성공하면 액세스 토큰 전달
  4. 웹 서버가 액세스 토큰을 사용하여 외부 애플리케이션의 API 사용

 

사용 유형

써드 파티 애플리케이션의 API를 직접적으로 사용하는 경우처럼

캘린더나 지도 등의 외부 API를 사용하는 애플리케이션을 이용할 때 사용된다.

 

사용자의 크리덴셜 정보를 남기고 싶지 않은 경우에도

OAuth 2.0을 사용하여 추가적인 인증 서비스를 사용할 수 있다.

 

728x90

이전에 폼 로그인 방식의 로그인/로그아웃을 구현하면서 간단하게 구조를 분석해 보았지만 

시큐리티를 배우는 과정에서 좀 더 정확하게 배우고 넘어가야 할거 같아서

공식문서를 참고하며 구조를 처음부터 정확하게 분석해 보겠다.

 

전체적인 흐름

 

 

위의 이미지는 공식문서에서 제공해 주는 클라이언트의 요청부터 스프링 시큐리티의 필터가 처리되는 과정이다.

ServletFilterChain
	ServletFilter
		DelegatingFilterProxy
			FilterChainProxy
				SecurityFilterChain
					SecurityFilter (ExceptionTranslationFilter, etc...)

이미지에 나타난 구조를 계층으로 표현하면 위와 같다.

 

코드로 살펴보기 전에 위의 과정을 글로 간단하게 정리해보겠다.

 

클라이언트가 서버에 요청을 보내면 서블릿 컨테이너는 필터 체인과 서블릿 생성

  • 필터체인은 필터 인스턴스들을 포함한다.
  • 서블릿은 요청 URI 경로를 기반으로 HttpServletRequest를 처리한다.
  • Spring MVC에서 서블릿은 DispatcherServlet의 인스턴스를 의미한다.
  • 실제 필터의 동작은 서블릿 필터에 전달되는 스프링 시큐리티의 필터 체인이 수행한다.

 

 

DelegatingFilterProxy를 통해 서블릿 컨테이너와 스프링 컨테이너를 연결

  • 서블릿 컨테이너와 스프링 컨테이너는 서로 다른 영역이다.
  • 스프링 시큐리티의 필터 체인은 스프링 컨테이너에 존재한다.
  • 스프링 컨테이너에 빈으로 등록되어 있는 필터 체인을 사용하기 위한 다리 역할이다.
  • 즉, 스프링 컨테이너에서 필터의 빈을 조회하고 호출한다.

 

FilterChainProxy를 통한 스프링 시큐리티 필터 체인 관리 및 실행

  • 스프링 시큐리티에서 제공하는 특수한 필터다.
  • SecurityFilterChain을 통해 필터 인스턴스들을 위임한다.
  • FilterChainProxy는 빈이기 때문에 DelegatingFilterProxy에 래핑 된다.
  • 등록된 필터 체인을 순서대로 실행한다.

 

SecurityFilterChain을 통한 스프링 시큐리티 필터 선택

  • 현재 요청에 대해 FilterChainProxy가 어떤 스프링 시큐리티 필터를 사용할지 결정한다.

 

SecurityFilter 삽입

  • SecurityFilterChain API를 사용해 FilterChainProxy에 삽입한다.
  • 필터의 순서는 아래와 같다.
  • 더보기
    ForceEagerSessionCreationFilter
    ChannelProcessingFilter
    WebAsyncManagerIntegrationFilter
    SecurityContextPersistenceFilter
    HeaderWriterFilter
    CorsFilter
    CsrfFilter
    LogoutFilter
    OAuth2AuthorizationRequestRedirectFilter
    Saml2WebSsoAuthenticationRequestFilter
    X509AuthenticationFilter
    AbstractPreAuthenticatedProcessingFilter
    CasAuthenticationFilter
    OAuth2LoginAuthenticationFilter
    Saml2WebSsoAuthenticationFilter
    UsernamePasswordAuthenticationFilter
    DefaultLoginPageGeneratingFilter
    DefaultLogoutPageGeneratingFilter
    ConcurrentSessionFilter
    DigestAuthenticationFilter
    BearerTokenAuthenticationFilter
    BasicAuthenticationFilter
    RequestCacheAwareFilter
    SecurityContextHolderAwareRequestFilter
    JaasApiIntegrationFilter
    RememberMeAuthenticationFilter
    AnonymousAuthenticationFilter
    OAuth2AuthorizationCodeGrantFilter
    SessionManagementFilter
    ExceptionTranslationFilter
    AuthorizationFilter
    SwitchUserFilter

 

ExceptionTranslationFilter을 통한 예외처리

  • AuthenticationException과 AccessDeniedException를 HTTP 응답으로 변환 가능하다.
  • SecurityFilter 중 하나로 FilterChainProxy 삽입된다.
  • AuthenticationException라면 인증을 시작한다.
  • AccessDeniedException라면 접근을 거부한다.

 

인증 간의 요청 저장

요청에 인증이 없거나 필요한 경우 인증 성공 후 다시 요청을 하려면

기존 요청에 대한 정보를 가지고 있어야 한다.

 

스프링 시큐리티에서는 RequestCache를 구현하여 HttpServletRequest를 저장한다.

 

RequestCache에 HttpServletRequest 저장

HttpServletRequest가 저장된 후에 사용자가 인증에 성공하면

RequestCache에 저장된 HttpServletRequest가 재사용 된다.

 

기본적으로 RequestCacheAwareFilter가 RequestCache를 사용해

HttpServletRequest를 저장하는 역할을 수행한다.

'Back-End > Security' 카테고리의 다른 글

OAuth 2.0 동작 방식  (0) 2023.07.17
OAuth 2.0  (0) 2023.07.17
JWT  (0) 2023.07.12
토큰 기반 자격 증명  (0) 2023.07.11
[스프링 시큐리티] 접근 제어 표현식  (0) 2023.07.11
728x90

JWT (JSON Web Token)는 이름 그대로 JSON 포맷을 사용하여

데이터를 안전하고 간결하게 전송하는 표준 인증 방식이다.

 

JSON 포맷의 토큰 정보를 인코딩 하고, 인코딩 된 토큰 정보를

비밀키로 서명한 메시지를 Web Token으로 인증 과정에 사용한다.

 

JWT의 종류

Access Token

사용자의 이메일, 연락처, 사진 등과 같은

보호된 정보에 접근할 수 있는 권한 부여에 사용된다.

 

클라이언트가 처음 인증을 받으면 

Access Token과 Refresh Token을 모두 받지만

실제 권한을 얻는데 사용되는 토큰은 Access Token이다.

 

사실상 권한을 부여 받을 때는 해당 토큰만 있어도 상관 없지만

해당 토큰을 탈취 당하는 경우에는 탈취한 쪽에서도

해당 토큰을 사용해 권한을 얻을 수 있기 때문

이 토큰의 유효 기간은 짧게 지정해둔다.

 

Refresh Token

실제 권한을 얻을 때 사용되지는 않지만

유효 기간이 짧은 Access Token을 재발급 받을 때 사용한다.

 

별도의 재인증 없이 해당 토큰을 사용하여

Access Token 토큰을 재발급 받을 수 있다는 장점이 있지만

재인증 없이 다시 기존의 권한들을 사용할 수 있다는 것이

보안적으로는 좋지 않기도 하다.

 

그렇기 때문에 사용자의 편의를 중요하게 생각하면

Refresh Token을 사용하여 재발급을 편하게 할 수도 있고

보안을 더 중요하게 생각하면 해당 토큰을 사용하지 않기도한다.

 

JWT의 구조

aaaaaa.bbbbbb.cccccc
(Header).(Payload).(Signature)

JWT는 위와 같이 점으로 세 부분으로 구분된다.

JSON 객체를 base64 방식으로 인코딩하면 JWT의 각 부분이 완성된다.

 

Header

{
	"alg": "HS256",
  	"typ": "JWT"
}

해당 토큰이 어떤 종류의 토큰이고 어떤 알고리즘으로 Sign할지 정의하는 부분이다.

 

Payload

{
    "sub": "someInformation",
    "name": "phillip",
    "iat": 151623391
}

서버에서 활용 가능한 사용자의 권한이나 정보 같은 데이터 등을 담을 수 있다.

가급적 민감한 정보는 담지 않는 것이 좋다.

 

Signature

Signature에서 원하는 비밀키Header에서 지정한 알고리즘으로

Header와 Payload의 데이터를 단방향 암호화 한다.

 

암호환된 메시지는 토큰의 위변조 유무 검증에 사용된다.

 

토큰 기반 인증 절차

  1. 클라이언트가 서버에 로그인 정보를 담아 요청을 보냄
  2. 로그인 정보 일치 확인
  3. 일치하면 암호화된 토큰 생성 (Access Token, Refresh Token)
  4. Refresh Token은 Access Token을 재발급 하는 용도기 때문에 같은 정보를 담지 않음
  5. 토큰을 클라이언트에 전송
  6. 클라이언트는 로컬 저장소, 세션 저장소, 쿠키 등에 토큰을 저장
  7. 클라이언트는 이후 HTTP Header나 쿠키에 토큰을 담아 요청에 사용

 

장점

확장에 유리하다

서버가 클라이언트에 대한 정보를 저장하지 않고 검증만 한다.

 

세션은 여러 대의 서버를 이용한 서비스인 경우에는

서버마다 세션에 대한 정보를 저장하고 있어야 하지만

토큰을 사용하면 그럴 필요가 없다.

 

클라이언트의 요청마다 인증을 할 필요가 없다

세션 같은 경우는 요청을 전송할 때마다 쿠키에 인증 정보를 포함하지만

토큰은 만료되기 전까지 한 번의 인증만으로 충분하다.

 

인증 시스템을 서버와 분리할 수 있다

구글이나 카카오 같은 다른 플랫폼의 자격 증명 정보로 인증하는 것이 가능하다.

토큰 생성용 서버를 만들거나 다른 플랫폼에 토큰 관련 작업을 맡기는 등

다양한 활용이 가능하다.

 

권한 부여에 용이하다

Payload에 사용자의 권한 정보를 포함하는 것이 용이하다.

 

단점

디코딩이 용이하다

Payload는 base64로 인코딩 되어 디코딩하기도 쉽기 때문에

민감한 정보는 포함하지 않는 것이 좋다.

 

토큰의 길이가 네트워크에 부하를 준다

토큰에 저장하는 데이터가 많아질수록 토큰의 길이가 늘어나는데

요청을 전송할 때마다 토큰을 전송하기 때문에

길이가 긴 토큰을 전송하는 것은 네트워크에 부하를 준다.

 

자동으로 삭제되지 않는다

한 번 생성된 토큰은 자동으로 삭제되지 않아서 만료 시간을 반드시 지정해야 한다.

너무 길지도 짧지도 않은 적당한 기간을 지정하는 것이 좋다.

728x90

HTTP 프로토콜의 비상태성 특성의 단점을 해결하기 위해

기존에는 세션을 사용하여 상태를 유지하는 방법을 사용했다.

 

세션 기반 자격 증명

세션 기반 자격 증명 방식은 서버 측에 인증된 사용자의 정보를

세션 형태로 세션 저장소에 저장한 후에 클라이언트 측에서 요청을 하면

세션 저장소의 세션과 사용자가 제공하는 정보가 일치하는지 확인한다.

 

즉, 인증된 사용자의 정보를 서버 측에서 관리하고

클라이언트 쪽은 세션 ID만 사용하여 상대적으로 적은 네트워트 트래픽을 사용한다.

 

서버 측에서 세션 정보를 관리하여 보안성 측면에서도 유리하다고 볼 수 있지만

서버의 확장성 면에서 세션 불일치 문제가 발생할 수도 있고

세션의 데이터가 많아질수록 서버의 부담이 가중된다.

 

CSR 방식보다는 SSR 방식에 적합한 방식이다.

 

토큰 기반 자격 증명

토큰은 티켓이나 입장권을 떠올리면 이해하기 쉽다.

 

현실에서 어떤 무언가를 이용할 때 사용자는 돈을 지불하여

무언가를 이용할 권한(토큰)을 얻는다.

 

여기서 돈을 지불하는 것

사용자가 Credential로 로그인 정보를 주는 것에 해당하고

지불한 돈에 맞는 권한을 얻는 것을 토큰에 해당한다.

 

여기서 세션 기반 자격 증명과 다른 점은

인증 정보(세션)를 서버 측에서 갖고 있는 것이 아닌

사용자가 직접 토큰을 갖고 있는 것이다.

 

세션 기반 방식에서는 사용자는 세션 아이디만 가지고

서버 측에 요청을 했다면 토큰 방식은 이와 반대로

클라이언트가 토큰으로 모든 인증된 사용자 정보를 가지고 요청하기 때문에

세션 방식에 비해 많은 네트워크 트래픽을 사용한다.

 

서버 측에서 세션을 관리하지 않기 때문에 보안적으로는 불리하지만

세션처럼 인증된 사용자 요청 상태를 유지할 필요가 없어

서버의 확장에 유리하고 세션 불일치 같은 문제가 없다.

 

클라이언트 측에서 토큰에 암호화 되지 않은 상태의

사용자 정보를 가지고 있기 때문에 민감한 정보는 포함하지 않는 것이 좋다.

 

한 번 발급한 토큰은 만료되기 전까지 무효화가 불가능하다.

 

CSR 방식에 적합하다.

 

단순하게 세션 방식의 특징과 정반대라고 생각하면 편하다.

728x90
hasRole(Stirng role) 현재 보안 주체가 지정된 역할을 갖고 있는지 여부 확인
파라미터로 넘긴 role이 ROLE_로 시작하지 않으면 추가
DefaultWebSecurityExpressionHandler의 defaultRolePrefix를
수정하여 커스텀 할 수 있다.
hasAnyRole(String… roles) 지정한 역할 하나라도 갖고 있는지 여부 확인
hasAuthority(String authority) 지정한 권한을 갖고 있는지 여부 확인
hasAnyAuthority(String… authorities) 지정한 권한 중 하나라도 갖고 있는지 여부 확인
principal 현재 사용자를 나타내는 principal 객체에 직접 접근 가능
authentication encurityContext로 조회할 수 있는
Authentication 객체에 직접 접근 가능
permitAll 모든 권한 허용
denyAll 모든 권한 차단
isAnonymous() 현재 보안 주체가 익명 사용자인지 확인
isRememberMe() 현재 보안 주체가 Remember-Me 사용자인지 확인
isAuthenticated() 사용자가 익명이 아닌지 확인
isFullyAuthenticated() 사용자가 익명 혹은 Remember-Me 사용자가 아닌지 확인
hasPermission(Object target, Object permission) 사용자가 타겟에 해당 권한(permission)이 있는지 확인
hasPermission(Object targetId, String targetType, 
Object permission)

 

+ Recent posts