쿠키(cookie)를 이용한 세션기반의 인증의 경우 특정 웹서버에서 세션 상태(session state)를 유지해야 하기 때문에 stateless 하지않다. 서버 로직이 Stateless가 아닌 경우 더 많은 요청을 처리하기 위해 동일한 서버의 숫자를 늘리는 스케일 아웃(scale out)에 적합하지 않다. 또한 도메인이 다른 서버에 대해서는 해당 세션 쿠키가 공유되지 않기 때문에 도메인이 다른 서버에 요청하기 위해서는 매번 새롭게 인증을 해야하는 불편함도 존재한다.
이 문제를 해결하기 위해 매번 http 요청마다 http header에 인증 토큰(authorization token)을 같이 보내는 형태의 방법을 많이 사용한다. 일반적으로 토큰 안에는 어떤 유저가 보내는 요청인지 구분하기 위해서 유저 ID값이 포함된다. 이 방법을 사용하면 서버쪽에서 세션 상태를 유지할 필요가 없어서 스케일 아웃에 적합하며, 도메인이 다른 서버에 요청하는 경우에도 동일한 토큰을 그대로 사용할 수 있다. 이러한 토큰기반의 인증을 적용하는 경우 악의적인 유저가 다른 유저ID를 사칭하는 것을 방지하기 위해서 토큰에 서명(signature)을 포함하거나, 대칭키 암호화를 적용한다.
이러한 방식은 API 서버를 개발하는 많은 사람들이 공통으로 많이 사용하다 보니 중복된 개발을 막기 위해서 JWT (JSON Web Token)라는 표준이 만들어지게 되었다. 실제로 직접 API 서버를 개발하거나 Auth0, AWS Cognito 등의 인증 서비스를 제공하는 플랫폼에서도 JWT가 많이 사용되고있다.
aud 필드에 포함하면 되고, 다음과 같은 절차를 따른다.
보호하려고 하는 데이터가 모두 하나의 key로 암호화 되어있는 경우 해당 key가 유출되면 모든 데이터가 유출되게 된다. 이러한 위험성을 줄이기 위해서 위해서 주기적으로 key를 변경하는 것을 key rotation 이라고 한다. 이 경우 특정 key가 유출되더라도, 특정 기간동안에 생성된 데이터만 유출되고, 다른 key로 암호화된 데이터는 안전하다.
일반적인 인증서의 경우 1~2년 정도의 유효기간을 가지게 된다. 인증서 마이그레이션을 위해 보통 구버전의 인증서가 만료되는 시점과 새로운 인증서의 유효기간을 겹치도록 새 인증서를 발급하고, 겹치는 기간동안은 두 인증서를 모두 지원해야 한다. 결국 인증서도 public key, private key의 조합이기 때문에 이러한 절차도 key rotation이라고 볼 수 있다.
RSA public key는 modulus와 public exponent로 구성되어 있다. 때문에 n, e 값이 주어지면, public key가 주어진 것이나 마찬가지이다.
private key에는 n, e 정보가 둘다 있기때문에 private key만 있으면 public key를 추출해 낼 수 있다.
RFC 3447에 정의된 ASN.1 형식을 보면 RSA public, private key 의 구성 요소들을 알 수 있다.
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER, -- (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}
AWS에서 제공하는 Cognito User Pool 인증을 통해서 발급받은 JWT를 이용하여 API 서버에서도 인증을 구현하고싶다면 어떻게 하면 될까?
흐름을 간단히 요약하면 다음과 같다.
위 프로세스를 진행하기 위해 AWS Cognito User Pool 기준으로 다시 필요한 내용을 정리해보자. JWT의 유효성 검증(verify) 하기 위한 AWS 가이드 에 나와있는 내용을 요약해보면 다음과 같다.
JWK URL에서 Public key키 가져오기
전달받은 JWT에서 SHA256(message)를 계산
전달받은 JWT의 signature를 public key로 복호화 하여 위의 값과 동일한지 확인 (signature는 SHA256(message)를 private key로 암호화한 값이기 때문)
추가로, Auth0에서 JWT, JWK를 활용하는 방식도 참고 할만 하다.