프로젝트/Profee

Spring Security & OAuth2.0 & JWT Token 소셜로그인 개념 정리

승요나라 2024. 8. 29. 14:30

Spring Security 란?

Spring Security는 애플리케이션의 보안을 담당하는 프레임워크로, 사용자의 인증(로그인)과 권한(접근 제어)을 관리해준다. 예를 들어, 누가 애플리케이션에 접근할 수 있는지, 어떤 기능을 사용할 수 있는지를 결정하는 역할을 한다.

 

왜 필요한가?
보안이 중요한 애플리케이션에서 사용자의 데이터 보호와 접근 제어를 쉽게 관리할 수 있도록 해준다.

 

동작 방식
Spring Security는 필터를 통해 요청이 들어올 때마다 이 요청이 인증된 사용자에 의해 이루어졌는지, 그리고 해당 사용자가 특정 리소스에 접근할 권한이 있는지를 확인한다.

 

 

 

OAuth2.0 이란?

OAuth(Open Authorization) 2.0은 인증 프로토콜로, 사용자가 자신의 자격 증명을 다른 서비스(예: 구글, 페이스북 등)와 안전하게 공유할 수 있게 한다. 즉, 인터넷 사용자들이 비밀번호를 제공하지 않고, 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로써 사용되는, 접근 위임을 위한 개방형 표준을 의미한다.

 그 중, OAuth2라고 불리우는 이유는 당연히도 이전 버전이 존재하기 때문이다. 2010년 IETF에서 'OAuth 1.0' 공식 표준안이 RFC 5849로 발표되었으며, OAuth의 세션 고정 공격을 보완한 'OAuth 1.0a'를 거쳐, 현재는 OAuth의 구조적인 문제점을 해결하고, 핵심 요소만을 차용한 유사 프로토콜 WRAP(Web Resource Access Protocol)을 기반으로 발표한 'OAuth 2.0(RFC 6749, RFC 6750)'가 많이 사용되고 있다.


왜 필요한가?
애플리케이션에서 직접 비밀번호를 입력받는 대신, 사용자가 이미 사용하고 있는 소셜 계정을 활용해 로그인을 구현할 수 있다. 이를 통해 보안이 강화되고 사용자 편의성이 높아진다.

 

동작 방식
OAuth 2.0은 "Access Token(엑세스 토큰)"이라는 임시 자격 증명을 발급한다. 이 토큰을 통해 애플리케이션이 사용자의 소셜 계정 정보에 접근할 수 있게 한다. 예를 들어, 사용자가 구글 계정으로 로그인하면, 구글이 해당 사용자를 인증하고 엑세스 토큰을 애플리케이션에 제공해준다. 이 토큰을 통해 애플리케이션은 사용자의 기본 정보를 가져올 수 있다.

 

 

OAuth2.0 주요 용어

용어 설명 예시
Resource Owner
(리소스 소유자)
사용자를 의미함.
OAuth 2.0에서 리소스 소유자는 자신의 리소스(데이터)를 보호하기 위해 권한을 부여하는 주체임.
ex) 사용자(예: 구글 계정을 가진 사람).
Client
(클라이언트)
리소스 소유자를 대신하여 리소스 서버에 접근하려는 애플리케이션.
클라이언트는 리소스 소유자의 권한을 얻기 위해 OAuth 2.0 프로세스를 사용함.
ex)  사용자가 로그인하려는 애플리케이션(예: 웹 애플리케이션, 모바일 앱).
Authorization Server
(인증 서버)
사용자를 인증하고, 클라이언트에게 엑세스 토큰을 발급하는 서버.
OAuth 2.0에서 중요한 역할을 함.
ex)  구글, 페이스북 등의 인증 서버.
Resource Server
(리소스 서버)
보호된 리소스를 호스팅하고, 클라이언트가 엑세스 토큰을 사용해 이 리소스에 접근할 수 있도록 허용하는 서버. ex)  구글의 사용자 데이터 API 서버.
Authorization Grant
(권한 부여)
클라이언트가 엑세스 토큰을 얻기 위해 Authorization Server에 제공하는 자격 증명.
OAuth 2.0에는 네 가지 권한 부여 방식이 있음.

  • Authorization Code (권한 코드): 일반적으로 웹 애플리케이션에서 사용되며, 가장 안전한 방식.
  • Implicit (암시적): 클라이언트 측 애플리케이션에서 사용되며, 보안이 다소 낮음.
  • Resource Owner Password Credentials (리소스 소유자 비밀번호 자격 증명): 사용자가 자신의 자격 증명을 클라이언트에 직접 제공하는 방식으로, 보안성이 낮아 잘 사용되지 않음.
  • Client Credentials (클라이언트 자격 증명): 클라이언트가 리소스 소유자 없이 리소스 서버에 접근할 때 사용됨.
→  Authorization Code Grant 방식이 OAuth2.0에서 가장 보편적으로 사용되는 인증 방식임.
Access Token
(엑세스 토큰)
클라이언트가 리소스 서버에서 보호된 리소스에 접근할 수 있도록 허용하는 토큰.
엑세스 토큰은 일반적으로 짧은 유효 기간을 가짐.
ex) 사용자가 구글 계정으로 로그인한 후, 애플리케이션이 구글 API에 요청할 때 사용하는 토큰.
Refresh Token
(리프레시 토큰)
엑세스 토큰이 만료된 후, 새로운 엑세스 토큰을 발급받기 위해 사용하는 토큰.
리프레시 토큰은 일반적으로 엑세스 토큰보다 더 긴 유효 기간을 가짐.
ex)  엑세스 토큰이 만료된 후에도 사용자가 다시 로그인하지 않고, 자동으로 새로운 엑세스 토큰을 받는 과정에서 사용됨.
Redirect URI
(리다이렉트 URI)
인증 서버가 권한 부여 결과(예: 엑세스 토큰 또는 권한 코드)를 클라이언트에게 전달하기 위해 사용되는 URL. ex)  사용자가 구글 로그인 후 다시 애플리케이션으로 돌아올 때 리다이렉트되는 URL.
Scope
(스코프)
클라이언트가 리소스 소유자의 어떤 데이터에 접근할 수 있는지 정의하는 권한의 범위. ex)  애플리케이션이 사용자의 이메일 주소와 프로필 정보에만 접근할 수 있도록 하는 스코프.
State
(상태)
클라이언트가 요청을 보낼 때 추가하는 값으로, 권한 부여 과정에서 CSRF 공격을 방지하기 위해 사용됨.
인증 완료 후 리다이렉트 시 동일한 상태 값이 반환되도록 함.
ex)  OAuth 2.0 인증 과정에서 보안을 강화하기 위한 임의의 문자열.

 

 

OAuth2.0 Authorization Code Grant Process

출처 : https://wildeveloperetrain.tistory.com/247

OAuth 2.0의 Authorization Code Grant Process는 사용자가 제공자(프로바이더)로부터 인증을 받고, 그 결과로 클라이언트 애플리케이션이 엑세스 토큰을 발급받아 보호된 리소스에 접근하는 과정이다. 이 과정은 다음과 같은 단계로 이루어진다.

 

1. 클라이언트가 인증 서버에 접근 권한 요청

  • 클라이언트(예: NEO 백엔드)는 OAuth 2.0 제공자(Authorization Server)에 접근 권한을 요청한다.
  • 요청 시 client_id, redirect_uri, response_type=code를 쿼리 파라미터로 포함한 요청을 전송한다.
  • 이 요청은 사용자를 제공자의 로그인 페이지로 리다이렉트 시키며, 사용자는 제공자에서 로그인하게 된다.
  • 예시: 카카오, 네이버 로그인 폼이 팝업 형태로 나타난다.

2. 사용자가 인증을 시도

  • Resource Owner(사용자)가 제공자(Authorization Server)에서 로그인 폼을 통해 인증을 시도한다.
  • 사용자가 성공적으로 로그인하면, 제공자는 Authorization Code(권한 부여 승인 코드)를 발급한다.
  • 이 코드가 클라이언트 애플리케이션이 제공한 redirect_uri로 전달된다.

3. 클라이언트가 엑세스 토큰 요청

  • 클라이언트는 발급받은 Authorization Code를 사용해, Authorization Server에 엑세스 토큰을 요청한다.
  • 이때 client_id, redirect_uri, grant_type=authorization_code, code(Authorization Code)를 포함한 요청을 전송한다.
  • 인증 서버가 요청을 검증한 후, 성공적으로 처리되면 클라이언트에게 OAuth 2.0 엑세스 토큰을 발급한다.

4. 클라이언트가 리소스 서버에 접근

  • 클라이언트는 발급받은 엑세스 토큰을 사용해, **Resource Server(자원 서버)**에 보호된 리소스(예: 사용자 정보)를 요청한다.
  • 리소스 서버는 엑세스 토큰을 검증한 후, 클라이언트에게 리소스를 제공하게 된다.

정리

  1. 클라이언트는 인증 서버에 접근 권한을 요청하며, 사용자는 제공자의 로그인 페이지로 이동한다.
  2. 사용자가 로그인에 성공하면, 인증 서버는 클라이언트에게 권한 부여 코드를 전달한다.
  3. 클라이언트는 이 코드를 사용해 엑세스 토큰을 요청하고, 엑세스 토큰을 발급받는다.
  4. 발급받은 엑세스 토큰을 통해 클라이언트는 리소스 서버에서 보호된 리소스에 접근한다.

 

 

Access Token을 획득하는 과정에서 Authorization Code 발급 과정이 들어간 이유

Authorization Code Grant 방식에서 Authorization Code를 사용하는 이유는 보안을 강화하기 위해서이다.

만약 Access Token을 바로 발급받는다면, 이 토큰이 브라우저 URL에 노출될 수 있다. URL에 노출된 토큰은 쉽게 탈취될 위험이 있다.

하지만 Authorization Code를 먼저 발급받고, 이 코드를 통해 서버 간 통신으로 Access Token을 발급받으면, 중요한 데이터인 Access Token이 브라우저에 노출되지 않아 보안이 더 안전해진다.

 

즉, Authorization CodeAccess Token을 안전하게 발급받기 위한 중간 단계로, 이를 통해 토큰 탈취 위험을 줄이는 역할을 한다.

 

 

Spring OAuth2 Client 란?

Spring OAuth2 Client는 OAuth 2.0 클라이언트로서 애플리케이션이 쉽게 소셜 로그인과 같은 OAuth 2.0 기반의 인증 기능을 구현할 수 있도록 돕는 Spring Security의 확장 라이브러리이다. 이 라이브러리를 사용하면, OAuth 2.0 프로세스를 간편하게 설정하고 관리할 수 있으며, 개발자는 복잡한 구현 없이 다양한 OAuth 2.0 제공자(예: 구글, 페이스북, 깃허브 등)와 연동할 수 있다.

 

Spring OAuth2 Client의 주요 기능

  • 자동 로그인 엔드포인트 생성
  • Authorization Code Grant Flow 자동 처리
  • 엑세스 토큰 관리 및 사용
  • 보안 구성 통합

 

만약 OAuth2 Client 라이브러리가 없다면 각 프로바이더들의 API Docs를 확인해서, 각 과정에 해당하는 API를 직접 통신하려 RestTemplete나 WebClient를 사용하고, 엔드포인트 생성을 위한 컨트롤러 생성 등의 클래식한 구현이 필요할 것이다.

 

따라서, Spring OAuth2 Client를 사용한다면 소셜 로그인과 같은 OAuth 2.0 기반의 인증 기능을 훨씬 수월하게 구현할 수 있다.

 

 

 

JWT Token 이란?

JWT(Json Web Token) 말 그대로 웹에서 사용되는 JSON 형식의 토큰 기반 인증 방식이다. 사용자의 인증 정보를 포함한 토큰을 생성하고, 이 토큰을 통해 사용자가 인증된 상태임을 유지할 수 있게 해준다.

JWT는 세 부분으로 구성된 문자열로, 사용자의 인증 정보를 안전하게 전송하기 위해 사용된다. 이 토큰은 주로 로그인 후 발급되며, 클라이언트는 이후 요청 시 이 토큰을 서버에 전송해 자신의 신원을 증명한다.


왜 필요한가?
JWT는 서버가 사용자 세션을 관리할 필요 없이, 클라이언트와 서버 간에 인증 정보를 안전하게 전달할 수 있다. 특히 분산 시스템에서 서버 간 인증 정보를 쉽게 공유할 수 있다는 장점이 있다.

 

동작 방식
JWT는 세 부분(헤더, 페이로드, 서명)으로 구성된 토큰이다. 사용자가 로그인하면 서버는 이 토큰을 생성해 사용자에게 제공한다. 이후 사용자가 서버에 요청을 보낼 때마다 이 토큰을 함께 전송하며, 서버는 토큰을 검증해 사용자가 인증된 상태인지 확인한다.

 

 

JWT Token의 구조

JWT"."(점)으로 구분된 세 가지 부분으로 나뉜다.

  1. Header (헤더): 토큰의 타입과 사용된 서명 알고리즘 정보를 포함한다.
    • 예: { "alg": "HS256", "typ": "JWT" }
  2. Payload (페이로드): 사용자의 인증 정보와 같은 클레임(claims)을 담고 있다. 주로 사용자 ID, 권한, 토큰 만료 시간 등의 정보가 포함된다.
    • 예: { "sub": "1234567890", "name": "John Doe", "admin": true }
  3. Signature (시그니쳐): 헤더와 페이로드를 합쳐 비밀 키로 서명한 부분으로, 토큰의 무결성을 검증하는 역할을 한다.
    • 예: HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

 

이 세 가지를 Base64로 인코딩한 후, "."(점)으로 연결한 것이 최종 JWT이다.

아래 예시에서 Encoded 파트가 전달되는 최종 JWT 토큰이라고 보면 된다.

출처 : https://hoons-dev.tistory.com/141

 

 

JWT 주요 특징

  • 자기 포함(Self-contained): JWT는 모든 인증 정보를 자체적으로 포함하고 있어, 서버는 별도의 세션 저장소를 유지할 필요가 없다.
  • 무결성 보장: 서명을 통해 토큰이 변조되지 않았음을 확인할 수 있다. 만약 페이로드가 변경되면 서명이 달라지므로, 서버는 이 토큰이 유효하지 않음을 즉시 알 수 있다.
  • 확장성: JWT는 다양한 클레임을 추가할 수 있어, 필요에 따라 확장이 가능하다. 예를 들어, 사용자 권한, 역할 등을 포함할 수 있다.

 

 

JWT Token을 사용하기 위해 알아야 할 것들

  • 토큰의 만료 시간 (Expiration Time)
    • JWT는 만료 시간을 설정할 수 있다. 토큰이 만료되면 사용자는 다시 인증을 받아야 한다. 만료 시간을 설정하지 않으면 보안상 위험할 수 있다.
  • 서명 알고리즘 (Signature Algorithm)
    • JWT는 다양한 서명 알고리즘을 지원한다. 가장 많이 사용되는 것은 HMAC SHA256(HS256)이며, 이 알고리즘을 사용하면 비밀 키를 기반으로 토큰의 무결성을 확인할 수 있다. RSA나 ECDSA와 같은 공개 키 암호화를 사용할 수도 있다.
  • 토큰 저장 위치
    • 클라이언트 측에서 JWT를 저장할 때는 XSS(크로스 사이트 스크립팅)와 같은 공격을 예방하기 위해 신중해야 한다. 일반적으로 HTTP 쿠키(Secure, HttpOnly 플래그 사용) 또는 브라우저의 로컬 스토리지에 저장한다. 그러나 각 방법에는 장단점이 있으므로 보안 요구사항에 따라 선택해야 한다.
  • 토큰의 보안
    • JWT 자체는 암호화되지 않기 때문에, 토큰 안에 민감한 정보를 담아서는 안 된다. 필요하다면, JWT 페이로드를 추가로 암호화하는 방법도 고려할 수 있다.
  • 토큰 무효화 (Invalidate Token)
    • JWT는 기본적으로 서버 측에서 상태를 관리하지 않기 때문에, 발급된 JWT를 무효화하는 것이 어렵다. 로그아웃이나 보안 사고 발생 시, 이를 처리하기 위한 전략이 필요하다. 예를 들어, 서버에서 블랙리스트를 관리하거나, 토큰의 유효성을 검증하는 데 필요한 메타데이터를 저장할 수 있다.

 

 

JWT 사용 시의 장점

  • 서버의 부담 감소: 세션을 서버에 저장할 필요가 없으므로, 확장성에 유리하다.
  • 다양한 클라이언트 지원: 웹, 모바일, 마이크로서비스 등 다양한 클라이언트에서 쉽게 사용할 수 있다.
  • RESTful 아키텍처에 적합: 무상태(stateless) 프로토콜인 REST와 잘 맞아 떨어진다.

JWT는 이러한 특징 덕분에 현대 웹 애플리케이션에서 널리 사용되며, 특히 마이크로서비스 아키텍처에서 효율적으로 사용자 인증을 처리할 수 있다.

 

 

 

소셜 로그인 동작 과정

따라서, 앞으로 구현할 Spring Security, OAuth2.0, JWT Token을 활용한 소셜 로그인 동작 과정은 다음과 같다.

 

  1. 사용자가 로그인 요청: 사용자가 "구글로 로그인"과 같은 소셜 로그인 버튼을 클릭한다.
  2. OAuth2.0 인증 요청: Spring Security가 사용자를 소셜 제공자(예: 구글, 네이버)의 로그인 페이지로 리다이렉트한다.
  3. 사용자 인증: 사용자는 소셜 제공자에서 로그인한다.
  4. Authorization Code 발급: 소셜 제공자가 사용자를 인증하면, 클라이언트(Spring 애플리케이션)에 Authorization Code를 전달한다.
  5. Access Token 발급: Spring 애플리케이션이 이 Authorization Code를 사용해 Access Token을 소셜 제공자에게 요청하고 발급받는다.
  6. JWT Token 생성: Spring 애플리케이션은 받은 사용자 정보를 바탕으로 JWT Token을 생성하고, 이를 클라이언트(브라우저나 앱)에 전달한다.
  7. 인증 유지: 이후 클라이언트는 요청 시 이 JWT Token을 포함해 서버에 보내며, 서버는 토큰을 검증해 사용자의 인증 상태를 확인하고 요청을 처리한다.

 

 

 

더보기