JWT 6. 보안 강화

agnusdei·2023년 7월 28일
0

JWT(Jason Web Token)은 인증과 권한 부여를 위해 사용되는 컴팩트하고 자체적으로 기존 쿠키 기반 인증보다 안전한 토큰 방식입니다. 하지만, 보안 취약점이 존재하며, 이를 강화하기 위해 암호화와 서명 방법, 공개키/개인키를 이용한 보안, 그리고 JWT 강화를 위한 보안 정책에 대해 설명하겠습니다.

JWT 암호화와 서명 방법

1. JWT 암호화:

일반적으로 JWT는 Base64로 인코딩된 헤더, 페이로드 및 서명으로 구성됩니다. 암호화된 JWT는 서버에서만 복호화할 수 있으므로 민감한 데이터를 포함하거나 중요한 정보를 안전하게 전송할 수 있습니다. 대표적인 암호화 알고리즘으로는 RSA, AES 등이 있습니다.

RSA 암호화:

공개키와 개인키를 사용하여 암호화 및 복호화를 수행합니다. 서버는 개인키를 가지고 있고, 클라이언트는 공개키를 가지고 있습니다. 클라이언트는 토큰을 생성할 때 개인키로 서명하고, 서버는 해당 토큰을 검증할 때 공개키로 복호화하여 내용을 확인합니다.

AES 암호화:

대칭키 암호화 알고리즘으로, 토큰을 생성하고 검증하는 데에 같은 키를 사용합니다. 서버와 클라이언트 모두 이 키를 알고 있어야 합니다. AES는 빠르고 효율적인 암호화 방법이지만, 키 관리가 중요한 과제입니다.

2. JWT 서명:

JWT 서명은 토큰의 무결성을 보장하기 위해 사용됩니다. 서명을 통해 토큰이 클라이언트나 중간자에 의해 변조되지 않았음을 검증할 수 있습니다. 서명에는 HMAC과 RSA가 주로 사용됩니다.

HMAC 서명:

HMAC은 대칭키를 사용하는 서명 방식으로, 토큰의 헤더와 페이로드를 해싱한 뒤 서버에 저장된 시크릿 키로 추가적인 해싱을 수행합니다. 검증 시 클라이언트와 서버가 동일한 시크릿 키를 알고 있어야 합니다.

RSA 서명:

RSA 서명은 비대칭키를 사용하는 서명 방식으로, 서버는 개인키로 토큰을 서명하고, 클라이언트는 공개키로 검증합니다. 이로 인해 토큰의 무결성과 인증이 보장됩니다.

공개키/개인키를 이용한 JWT 보안

RSA 서명 방식은 공개키/개인키 기반으로 작동합니다. 서버는 개인키를 안전하게 보관하고, 클라이언트는 공개키를 사용하여 서버에서 받은 JWT를 검증합니다. 이러한 방식으로 JWT의 무결성과 신뢰성을 확보할 수 있습니다.

  1. 서버 측 과정:
    • 서버는 RSA 키 쌍을 생성하고 개인키를 안전한 저장소에 보관합니다.
    • 클라이언트가 인증되어 로그인하면, 서버는 개인키를 사용하여 JWT를 서명합니다.
import jwt
import datetime

private_key = """-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA2C... (개인키) ...tMw4c9KthtTRg7c6Gw==
-----END RSA PRIVATE KEY-----"""

payload = {
    'user_id': '1234567890',
    'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=30)
}

token = jwt.encode(payload, private_key, algorithm='RS256')
  1. 클라이언트 측 과정:
    • 클라이언트는 공개키를 사용하여 서버에서 받은 JWT를 검증합니다.
import jwt

public_key = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2C... (공개키) ...V/HwCw
-----END PUBLIC KEY-----"""

token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9... (서명된 JWT) ...dUbo6YHg"

try:
    payload = jwt.decode(token, public_key, algorithms='RS256')
    print("Decoded payload:", payload)
except jwt.ExpiredSignatureError:
    print("Token has expired.")
except jwt.InvalidTokenError:
    print("Invalid token.")

JWT 강화를 위한 보안 정책

JWT 보안을 강화하기 위해 다음과 같은 보안 정책을 고려해야 합니다.

  1. 토큰 만료 시간 설정: JWT의 페이로드에 만료 시간을 포함하여, 토큰의 유효 기간을 설정합니다. 이렇게 함으로써 토큰의 수명을 제한하고 잠재적인 보안 위협을 줄일 수 있습니다.

  2. HTTPS 사용: JWT는 HTTP 통신을 통해 전송되기 때문에, HTTPS를 사용하여 통신을 암호화하고 중간자 공격을 방지합니다.

  3. 보안 헤더 설정: 적절한 보안 헤더를 설정하여 캐시 및 브라우저 XSS(Cross

-Site Scripting) 공격을 방지합니다.

  1. 토큰 리프레시: JWT를 사용하면 토큰이 만료되면 재인증이 필요합니다. 이때, 새로운 토큰을 발급하기 위한 리프레시 토큰을 사용하거나, OAuth2와 같은 프로토콜을 통해 토큰을 갱신합니다.

  2. 권한과 스코프 관리: JWT에는 클레임(claim)으로 권한과 스코프 정보를 포함시킬 수 있습니다. 이를 통해 토큰의 사용 범위를 제어하고 필요한 리소스에만 접근할 수 있도록 합니다.

  3. JWT 저장소 보안: 개인키와 시크릿 키 등 민감한 정보를 보관하는 서버의 저장소를 안전하게 관리합니다. 무단 접근을 방지하고 안전한 환경을 구성하는 것이 중요합니다.

  4. 토큰의 길이 제한: 토큰의 크기를 적절하게 제한하여 네트워크 오버헤드와 잠재적인 보안 위협을 줄입니다.

  5. JWT 갱신 정책: 토큰의 만료 시간이 다가오면, 클라이언트가 적시에 토큰을 갱신하는지 확인하는 정책을 수립합니다.

이러한 JWT 강화를 위한 보안 정책을 함께 사용하여 보안성을 높일 수 있습니다. 하지만 보안은 항상 변화하는 주제이므로, 최신 보안 업데이트를 지속적으로 적용하고, 신뢰성과 안정성을 유지하기 위해 보안 전문가와 협력하는 것이 중요합니다.

토큰 리프레시(토큰 갱신)와 OAuth 2.0은 모두 인증과 권한 부여를 위한 프로토콜과 방법론입니다. 각각에 대해 상세히 설명하겠습니다.

토큰 리프레시 (Token Refresh)

토큰 리프레시는 인증 토큰의 만료를 처리하고 새로운 토큰을 발급받는 기능입니다. 인증 토큰(JWT 등)은 일정 기간 동안 유효하며, 만료되면 클라이언트는 서버에 새로운 토큰을 요청해야 합니다. 하지만 사용자가 로그인 상태를 유지해야 할 때 매번 사용자에게 로그인 요청을 하면 불편하고 보안에 취약해집니다.

이런 문제를 해결하기 위해 토큰 리프레시를 사용합니다. 토큰 리프레시는 주로 "리프레시 토큰(Refresh Token)"이라는 추가적인 토큰을 사용하여 수행됩니다. 이 토큰은 보통 사용자의 인증 정보와 연관되어 있으며, 인증 토큰이 만료되었을 때 새로운 인증 토큰을 발급받는 데 사용됩니다.

일반적인 토큰 리프레시 과정:
1. 클라이언트가 인증하여 인증 토큰을 발급받습니다.
2. 인증 토큰의 만료 시간이 다가오면, 클라이언트는 리프레시 토큰을 사용하여 새로운 인증 토큰을 요청합니다.
3. 서버는 리프레시 토큰의 유효성을 확인한 뒤, 새로운 인증 토큰을 발급합니다.
4. 클라이언트는 이후에도 계속 리프레시 토큰을 사용하여 새로운 인증 토큰을 발급받습니다.

토큰 리프레시는 기존 인증 토큰보다 유효 기간이 상대적으로 길며, 보안 상의 이유로 HTTPS를 통해 전송되어야 합니다.

OAuth 2.0

OAuth 2.0은 제3자 애플리케이션이 다른 애플리케이션의 리소스에 접근 권한을 얻을 수 있도록 하는 인증 프로토콜입니다. OAuth 2.0은 주로 사용자의 소셜 미디어 계정, 온라인 서비스, API 등을 연동할 때 사용됩니다. 이를 통해 사용자는 자신의 인증 정보를 제3자에게 노출하지 않고도 제3자 앱에 접근 권한을 부여할 수 있습니다.

OAuth 2.0의 주요 구성요소:

  1. Resource Owner (리소스 소유자): 보호된 리소스에 접근하려는 사용자입니다. 예를 들어, 소셜 미디어 계정의 소유자가 리소스 소유자가 됩니다.

  2. Client (클라이언트): 제3자 애플리케이션입니다. 리소스에 접근 권한을 얻고자 하는 애플리케이션입니다.

  3. Authorization Server (인증 서버): 사용자의 동의를 받고, 클라이언트에게 액세스 토큰을 발급하는 역할을 합니다.

  4. Resource Server (리소스 서버): 보호된 리소스를 호스팅하는 서버입니다. 인증서버가 발급한 액세스 토큰을 검증하고, 요청한 리소스에 대한 접근 권한을 확인합니다.

OAuth 2.0 인증 흐름:

  1. 클라이언트가 인증 서버에 인증을 요청하고, 클라이언트 아이디와 시크릿을 제공합니다.

  2. 인증 서버는 사용자를 인증하도록 유도하고, 인증이 성공하면 사용자에게 권한 동의를 요청합니다.

  3. 사용자가 권한 동의를 하면, 인증 서버는 클라이언트에게 인증 코드를 발급합니다.

  4. 클라이언트는 인증 코드를 사용하여 인증 서버에 액세스 토큰을 요청합니다.

  5. 인증 서버는 클라이언트에게 액세스 토큰을 발급합니다.

  6. 클라이언트는 액세스 토큰을 사용하여 리소스 서버에 보호된 리소스에 접근할 수 있습니다.

OAuth 2.0은 다양한 인증 흐름이 존재하며, 애플리케이션의 요구 사항에 맞게 적절한 흐름을 선택하여 사용합니다.

profile
DevSecOps ⚙️ + Pentest 🚩

0개의 댓글