포스트

2023-12-12-TIL

2023-12-12-TIL

Today I Learned

JWT Structure

JWT(JSON Web Token)는 점(.)으로 구분된 세 부분으로 이루어진다. Auth0 문서의 설명은 이렇다.

  • 헤더(JOSE Header): 토큰 종류와 서명에 쓴 알고리즘(alg) 같은 메타데이터
  • 페이로드: 사용자 식별자나 권한처럼 검증 가능한 진술, 즉 클레임(claim)의 모음
  • 서명: Base64URL로 인코딩한 헤더와 페이로드를 비밀 키로 서명한 값. 보낸 쪽이 맞는지, 중간에 내용이 바뀌지 않았는지 확인하는 데 쓴다.

헤더와 페이로드는 암호화가 아니라 인코딩일 뿐이라 누구나 디코딩해서 읽을 수 있다. 그래서 문서는 JWT를 쓸 때 저장하거나 사용하기 전에 반드시 서명을 검증하라고 강조한다. 비밀번호 같은 민감한 값은 페이로드에 넣으면 안 된다.

  • https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-token-structure

JWT Use Cases

RFC 7519는 몇 가지 등록 클레임(registered claim)을 정의한다. 모두 선택 사항이다.

클레임의미
iss토큰을 발급한 주체
sub토큰의 주체. 발급자 안에서 유일하거나 전역적으로 유일해야 한다.
aud토큰을 받을 대상. 처리하는 쪽이 aud에 자기가 없으면 토큰을 거부해야 한다.
exp만료 시각
nbf이 시각 이전에는 받아들이지 않음
iat발급 시각
jti토큰 고유 ID. 재사용 방지에 쓴다.

Auth0의 클레임 문서는 이 밖의 클레임을 충돌을 피하도록 이름 붙인 공개 클레임과, 당사자끼리 합의해 쓰는 비공개 클레임으로 나눈다.

JWT가 늘 좋은 선택은 아니다. Evert Pot의 글은 세션의 기본값으로 JWT를 쓰지 말라고 주장한다. 표준이 복잡해 설정을 잘못하기 쉽고, 토큰이 자기 완결적이라 서버가 특정 토큰을 무효화할 방법이 없어 로그아웃이 어렵다는 것이다. 글은 보통 토큰 수명을 아주 짧게 하고 리프레시 토큰을 쓰거나, 폐기된 토큰 목록을 관리하는 방식으로 이를 푼다고 정리한다. 그러면 결국 중앙 저장소가 다시 필요해지는데, 그것이 바로 JWT가 없애려던 것이라고 지적한다.

  • https://datatracker.ietf.org/doc/html/rfc7519
  • https://jwt.io/introduction
  • https://velopert.com/2389
  • https://security.stackexchange.com/questions/256794/should-i-specify-jwt-audience-and-issuer-if-i-have-only-one-spa-client
  • https://www.loginradius.com/blog/engineering/guest-post/jwt-authentication-best-practices-and-when-to-use/
  • https://blog.logrocket.com/jwt-authentication-best-practices/
  • https://evertpot.com/jwt-is-a-bad-default/
  • https://documentation.softwareag.com/webmethods/compendiums/v10-11/C_API_Management/index.html#page/api-mgmt-comp/co-jwt_usecase_workflow.html
  • https://curity.io/resources/learn/jwt-best-practices/
  • https://www.linkedin.com/advice/3/how-do-you-use-jwt-claims-enforce-authorization
  • https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-token-claims

JWT Issuer (iss)

RFC 7519에 따르면 iss는 JWT를 발급한 주체를 나타내고, 대소문자를 구분하는 문자열이나 URI 값이다. 처리 방식은 애플리케이션이 정한다. 발급자가 여럿인 시스템에서는 검증하는 쪽이 iss를 보고 어느 발급자의 공개 키로 서명을 확인할지 고르고, 신뢰하는 발급자 목록에 없으면 거부한다.

  • https://mojoauth.com/glossary/jwt-issuer/

JWT Identifying Private, Admin Token

JWT 토큰을 통해서 내부에서 발급한 토큰인지 외부에서 발급한 토큰인지 확인해서 외부망에서 내부용 토큰을 사용하면 block 하도록 설정하고 싶다. 하지만 나의 상황에서 발급처(issuer)로 식별되는 내/외부 정보는 관리자 or 일반 사용자로 구분하는 기준과 동일하다. 즉, ‘관리자도 내부망을 통해서만 접근 가능하다’라는 요구사항이 있으므로 두 가지 방법 모두 동일하게 요구사항을 충족할 수있다.

하지만 아래와 같이 구분할 수 있는 속성을 추가한다고 해도 해당 속성을 조작할 수 있는 여지가 충분히 있다. 따라서 해당 속성의 암호화 등을 추가로 고려하면 더욱 안전하게 관리할 수 있다.

1
2
3
4
5
6
7
{
  "sub": "user123",
  "iss": "your_issuer",
  "aud": "your_audience",
  "internal": true,    // 내부망 여부
  "admin": false       // 관리자 여부
}

위 구조의 위험을 나눠 보면 조작과 노출은 다른 문제다. 서버가 서명을 검증한다면 비밀 키 없이 internal이나 admin 값을 바꾼 토큰은 서명이 맞지 않아 거부된다. 즉 조작은 서명 검증으로 막힌다. 반면 페이로드는 누구나 읽을 수 있으므로, 이런 값이 노출되는 것이 문제라면 서명이 아니라 암호화(JWE)가 필요하다. 그리고 내부·외부 구분처럼 신뢰 경계에 관한 판단은 토큰 안의 값만 믿기보다, 요청이 들어온 네트워크 경로(게이트웨이, 출발지 IP)와 iss·aud 검증을 함께 쓰는 편이 안전하다. 내부용 토큰과 외부용 토큰을 서로 다른 키나 다른 aud로 발급하면, 외부 게이트웨이가 내부용 토큰을 아예 받아들이지 않게 만들 수 있다.


MongoDB

MongoDB는 문서 지향 NoSQL 데이터베이스다. 테이블과 행 대신 JSON과 비슷한 문서를 컬렉션에 저장하고, 스키마는 선택적으로 둘 수 있다. 같은 컬렉션의 문서끼리 필드 구성이 달라도 되므로, 구조가 자주 바뀌거나 중첩된 데이터를 한 번에 읽어야 하는 경우에 잘 맞는다. 위키백과에 따르면 2018년 4.0.4 릴리스부터 라이선스가 AGPL 3.0에서 SSPL로 바뀌었다.

  • https://en.wikipedia.org/wiki/MongoDB
  • https://www.ibm.com/kr-ko/topics/mongodb
  • https://www.w3schools.com/mongodb/
  • https://www.linkedin.com/company/mongodbinc
  • https://twitter.com/MongoDB
  • https://jaehoney.tistory.com/314
  • https://appmaster.io/ko/blog/monggodibiran-mueosinga

JUnit5

JUnit 5 사용자 가이드는 JUnit 5를 세 하위 프로젝트의 합으로 설명한다.

  • JUnit Platform: JVM에서 테스트 프레임워크를 실행하는 기반이고, 테스트 엔진을 만들기 위한 TestEngine API를 정의한다.
  • JUnit Jupiter: JUnit 5로 테스트와 확장을 작성하는 프로그래밍 모델과 확장 모델이다. @Test, @BeforeEach, @ParameterizedTest 등이 여기에 속한다.
  • JUnit Vintage: JUnit 3와 4로 작성한 테스트를 플랫폼 위에서 돌리기 위한 엔진이다.

이렇게 나뉜 덕분에 IDE나 빌드 도구는 플랫폼 하나만 지원하면 여러 테스트 엔진을 함께 실행할 수 있다.

  • https://toneyparky.tistory.com/3
이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다