이 시리즈에서는 HTTP의 인증(Authentication)에 대해 다룹니다.
이번 글에서는 HTTP의 인증이 어떤 방식으로 발전되어 왔으며, JWT가 뭐고 무엇인지를 다루도록 하겠습니다.
헷갈리기 쉬운 인증과 인가부터 짚고 넘어가도록 하겠습니다.
인증
2xx
응답을, 실패했다면 4xx
응답을 받을 것입니다.인가
2xx
응답을, 올바르지 않다면 4xx
응답을 받을 것입니다.데이터를 받아보는 당신이 누구인지를 묻는 요구사항은 HTTP/1.0 스펙부터 등장하였습니다[1]. 1996년부터 등장했고 현재는 사용하지 않습니다. 다만 어떤식으로 발전했는지를 살펴봅시다.
BASIC
인증base64(유저명 + ":" + 패스워드)
로 인코딩하여 아래와 같은 방식으로 헤더에 추가합니다.Authorization: "Basic dXNlcjpwYXNz"
Digest
인증401
응답으로 거부를 받은 후, 거기서 얻은 정보를 가지고 재요청을 하는 것이 특징입니다.보호된 영역에 접속하려할 때, 401 Unauthorized
를 받고, 서버로부터 특정 값을 받습니다(handle_401
호출).
WWW-Authenticate: Digest realm="영역명", nonce="임의의값", algorithm="알고리즘명", qop="auth"
realm
)nonce
)qop
)nonce
를 통해 호출한 횟수 (nc
)유저는(사실은 유저의 클라이언트죠) A1
, A2
와, 무작위로 생성한 cnonce
라는 값을 토대로 response
를 계산합니다(build_digest_header
).
A1
: 유저명 ”:” realm ”:” 패스워드A2
: HTTP 메소드 ”:” 컨텐츠 URIresponse
: MD5(MD5(A1
) ”:” nonce ”:” nc ”:” cnonce ”:” qop ”:” MD5(A2
))서버측은 자신이 가진 유저명/패스워드와 위 과정에서 받은 정보를 가지고 “동일한”response를 계산하게 되면, 인증에 성공하게 됩니다.
이런 인증을 현대에 대응하기에는 무리가 있습니다. 이유는 아래와 같습니다.
이러한 사항 때문에, HTML의 Form
을 이용한 로그인과, 쿠키를 이용한 세션관리 조합으로 발달되게 되었습니다.
현대에까지 널리 사용되고 있는 브라우저 쿠키와 세션을 통한 인증이 있곘습니다. 아래에서 기본적인 개념을 살펴보겠습니다.
Expires
, Max-Age
속성)Domain
속성)Path
속성)HTTPS
를 통한 접속일 때만 서버로 쿠키를 전송 (Secure
속성)HttpOnly
속성)SameSite
속성, 비표준입니다!)여러 방법이 있겠습니다만, 장고에서 세션을 활용하는 방안은 여러가지가 있습니다.
세션을 어떤 식으로 관리할지에 대한 설정은 아래와 같습니다:
이어서 JWT입니다. 우선은 간략하게 JWT가 무엇인지 살펴보겠습니다.
JSON Web Token(JWT)는 2010년 10월 28일, 처음 발표되었습니다. 간략한 정보는 아래와 같습니다.
소개는 이쯤하고, 구조를 먼저 살펴본 후 사용례를 살펴봅시다.
JWT의 구조를 살펴봅시다. JWT는 헤더.페이로드.시그니처 의 세 부분으로 구성됩니다. .
은 구분자로 사용됩니다.
JWT는 이런 모양을 가집니다.
aaaaa.bbbbb.ccccc
보다 정확한 스펙은 상술한 RFC 문서를 참고해주세요.
두 가지 값을 가집니다.
HS256
이라는 값은, HMAC-SHA256
을 사용하여 이 토큰을 생성하였음을 의미합니다. 통상적으로 사용할 수 있는 알고리즘은 이 링크를 참고해주세요.JWT
를 사용하거나 스펙에 맞게 사용합니다.아래와 같은 모양으로 생겼습니다.
{
"alg": "HS256",
"typ": "JWT"
}
claim
의 모임입니다. 클레임은 크게 세 종류로 나눌 수 있습니다.
iss
: 누가 이 토큰을 발급했는지를 표기합니다.exp
: 만기 시간을 기재합니다. (단위: miliseconds가 반영된 Epoch time)sub
: 토큰의 발급 목적을 의미합니다.aud
: 토큰을 받는 사람을 의미합니다.nbf
: 연산의 이유로 이 시간 전에는 토큰이 유효하지 않다는 시간을 의미합니다. (단위: miliseconds가 반영된 Epoch time)iat
: 언제 이 토큰이 발급되었는지를 의미합니다.jti
: JWT 토큰의 고유ID 입니다. 중복되지 않는 값으로 생성시켜야 합니다.(!) claim: JWT에 의해 전달된 개별 값들이 구성원인 JSON 개체를 나타냅니다.
{
"sub": "1",
"name": "s3ich4n",
"admin": false
}
토큰이 유효한지 검증합니다. 시그니처는 RFC 4648(Base64Url)을 사용하여 헤더와 페이로드를 인코딩하기위해 계산됩니다. 그리고 구분자 .
을 이용하여 둘을(헤더, 페이로드) 합칩니다. 이후 공개키/비밀키(RSA나 ECDSA 등)나 shared secrets값(HAMC)을 통해 시그니처를 생성합니다.
예를들어 HMAC SHA-256 알고리즘을 사용한다면, 시그니처는 아래와 같이 생성됩니다.
HMAC_SHA256(
secret,
base64UrlEncode(header) + "." +
base64UrlEncode(payload)
)
이런 모양이 나옵니다.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYXQiOjE0MjI3Nzk2Mzh9.gzSraSYS8EXBxLN_oWnFSRgCzcmJmMjLiuyu5CSpyHI
이번 글을 통해, 아래 내용들을 살펴볼 수 있었습니다:
다음 글에서는 JWT가 어떤식으로 인증(및 인가)에 쓰이게 되는지, JWT의 특성을 오해하고 잘못 사용중인건 아닌지 살펴보겠습니다.
읽어주셔서 감사합니다.