본문 바로가기
BackEnd

인증(Authentication) Bcrypt와 JWT에 대해서

by SoriKim 2023. 11. 28.
반응형

1. Bcrypt란? 

'Bcrypt'는 브루스 슈나이어가 설계한 키(Key) 방식의 대칭형 블록 암호에 기반을 둔 암호화 해시 함수의 한 종류로 Niels Provos와 David Mazieres가 설계했습니다. 주로 비밀번호와 같은 민감한 정보를 안전하게 저장하기 위해 사용됩니다. 이는 단방향 해시 함수로, 일반적인 해시 함수와는 다르게 동일한 입력에 대해 항상 동일한 출력을 생성하지 않습니다. 이 특성은 보안상 중요하며, 일반적인 해시 함수는 동일한 입력에 대해 항상 동일한 해시 값을 생성하기 때문에 레인보우 테이블과 같은 사전 공격에 취약할 수 있습니다. 또한, 해시 함수는 본래 빠르게 데이터를 검색하기 위해 탄생되었습니다. 따라서, 공격자는 매우 빠른 속도로 임의의 문자열의 해시값과 해킹할 대상의 해시값을 비교하여 대상자를 공격할 수 있습니다. 이런 문제를 보안하기 위해 단방향 암호화를 진행할 때 솔팅(salting)과 키 스트레칭(Key Stretching)을 적용시킵니다. 

 

1️⃣ 솔팅(Salting)

'Bcrypt'는 각 비밀번호에 대해 무작위의 솔트 값을 생성해 해싱에 포함시킵니다. 솔트는 일종의 임의의 문자열로, 동일한 비밀번호라도 각각의 솔토 값이 다르기 때문에 최종 해시 값도 다르게 됩니다. 이로써 레인보우 테이블 공격과 같은 공격을 어렵게 만듭니다. 

 

2️⃣ 키 스트레칭 (Key Stretching)

단방향 해쉬값을 계산한 후, 그 해쉬값을 또 다시 해시하고 또 이를 반복하는 방식입니다. 

최근 일반적인 장비로 1초에 50억 개 이상의 해시값을 비교할 수 있지만, 키 스트레칭을 적용하면 동일한 장비에서 1초에 5번 정도만 비교할 수 있습니다. 

GPU(Graphics Processing Unit)를 사용하더라도 수백에서 수천 번 정도만 비교할 수 있습니다. 

 

3️⃣ Bcrypt 구조 

$2b$12$76taFAFPE9ydE0ZsuWkIZexWVjLBbTTHWc509/OLI5nM9d5r3fkRG
 \/ \/ \____________________/\_____________________________/
Alg Cost       Salt                        Hash
  • 2b: 해시 알고리즘 식별자 
  • 12: Cost Factor로 Key Stretching의 수(2의 12승 번)
  • 76taFAFPE9ydE0ZsuWkIZe: 16Byte 크기의 Salt, Base64로 인코딩 된 22개의 문자
  • xWVjLBbTTHWc509/OLI5nM9d5r3fkRG: 24Byte의 해시 값, Base64로 인코딩 된 31개의 문자 

4️⃣ 검증

'Bcrypt'는 단방향 해시 알고리즘으로 복호화가 불가능합니다. Bcrypt의 검증은 암호화된 값이 가지고 있는 알고리즘, Cost Factor, Salt를 이용합니다. 비교하고 싶은 평문을 암호화된 값이 가지고 있는 알고리즘, Cost Factor, Salt을 이용해 해시를 진행한 후 암호화된 값과의 비교를 통해 검증을 진행합니다. 

 

2. JWT란?

JWT(Json Web Token)는 웹에서 정보를 안전하게 전송하기 위한 표준을 정의하는 방법 중 하나입니다. 주로 클라이언트와 서버 간의 정보를 JSON 객체로 안전하게 전달하기 위해 사용되며 JWT는 RFC7519에 정의되어 있습니다. 

또한, SAML(Security Assertion Markup Language Token)보다 크기가 작아 더 컴팩트 하게 사용할 수 있습니다. 

JWT는 JSON 객체에 기본정보, 전달할 정보, 검증 정보를 모두 담고 있으며 전자 서명이 되어 있기 때문에 검증 과정을 거쳐 확인하고 신뢰할 수 있습니다. Secret Key 또는 Public/Private Key Pair를 사용하여 서명할 수 있습니다. 

 

 

1️⃣ JWT 구조 

JWT는 3가지 구성요소(Header, payload, Signature)로 이루어져 있으며, 각 구성 요소들은 dot(.)으로 구분되어 있습니다. 

 

JWT 구조

 

 

1) Header(헤더): JWT의 유형 및 사용하는 해시 알고리즘 등에 대한 메타데이터를 담는 부분

일반적으로 다음과 같이 JSON 형태로 표현됩니다. 

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

 

여기서 "alg"은 Signature를 만드는 데 사용된 해시 알고리즘을 나타내며, "typ"은 토큰의 타입을 나타냅니다. 

 

2) Payload(페이로드): 실제로 전송되는 데이터를 담고 있는 부분으로 클레임(Claim)이라 불리는 키-값 쌍들이 담겨 있습니다. 클레임은 세 가지 유형으로 나뉩니다. 

  • 등록된 클레임(Registered claims): 표준 클레임으로 7가지의 Registered Claim이 존재하며, 토큰에 대한 정보를 제공합니다. 예를 들어, 발급자(issuer), 만료 시간(expiration time), 발급 시간(issued at) 등이 있습니다.
  • 공개 클레임(Public claims): 사용자 정의 클레임으로, 충돌을 피하기 위해 네임스페이스를 사용하는 것이 좋습니다. 
  • 비공개 클레임(Private claims): 클라이언트와 서버 간에 협의된 정보를 담습니다. 

일반적인 예시

{
  "iss": "issuer",        // 발급자(issuer)
  "sub": "subject",       // 주체(subject)
  "aud": "audience",      // 대상(audience)
  "exp": 1516239022,      // 만료 시간(expiration time)
  "nbf": 1516239022,      // 토큰을 처리하기 시작하는 시간(not before)
  "iat": 1516239022,      // 토큰이 발급된 시간(issued at)
  "jti": "jwt_id",        // JWT ID

  // 사용자 정의 클레임 (Public Claims)
  "custom_namespace": {
    "user_id": 12345,      // 사용자 ID
    "role": "admin"        // 역할
  }
}

 

 

 

3) Signature(서명)

헤더와 페이로드를 인코딩하고, 비밀 키(Secret Key)를 사용해 서명합니다. 

서명은 헤더, 페이로드, 그리고 시크릿 키를 사용해 생성됩니다. 이 서명을 통해 토큰이 유효한지 여부를 검증할 수 있습니다. 

서버에서 관리하고 있는 Secret Key가 아닌 다른 Key로 JWT를 발급한다면 Signature가 달라지기 때문에 해당 JWT는 신뢰할 수 없는 토큰입니다. 

 

서명 생성 예시

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

 

반응형

댓글