LabHub
배우기 러닝패스 코스

企業認証の連携

OIDC認可コードフローを手で再現する

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

실습용 OIDC 제공자를 상대로 인가 코드 흐름을 직접 손으로 수행하고, ID 토큰을 디코드·서명 검증하고, 검증 체크리스트를 작성할 수 있게 됩니다.

왜 중요한가

OIDC 를 라이브러리로만 써 본 사람은 장애가 났을 때 어디를 봐야 할지 모릅니다. redirect_uri 불일치, state 미검증, nonce 누락, 만료된 코드 재사용 — 전부 흐름을 눈으로 본 적이 있어야 감이 옵니다. 특히 ID 토큰은 base64 라 누구나 디코딩할 수 있다는 사실을 손으로 확인하는 것이 중요합니다. 페이로드를 고쳐도 서명 검증을 안 하면 그대로 통과한다는 것을 직접 재현해 보면, 왜 alg 를 고정해야 하는지가 몸으로 남습니다.

단계

  1. 실습용 IdP 를 기동합니다. python3 /opt/lab/fixtures/auth/oidc/idp.py 9000 (백그라운드) discovery 문서를 받아 /root/oidc/discovery.json 에 저장합니다. (http://127.0.0.1:9000/.well-known/openid-configuration) issuer, authorization_endpoint, token_endpoint, jwks_uri 가 있어야 합니다.
  2. /root/oidc/auth-url.txt 에 authorization URL 한 줄을 적습니다. 필수 파라미터: response_type=code, client_id=labhub-web, redirect_uri=http://127.0.0.1:9100/callback, scope=openid profile email, state=<16자 이상>, nonce=<16자 이상>.
  3. 그 URL 을 리다이렉트를 따라가지 않고 호출해 응답의 Location 헤더를 /root/oidc/callback.txt 에 저장하고, 거기서 code 값만 뽑아 /root/oidc/code.txt 에 저장합니다. Location 의 state 는 2단계에서 보낸 값과 같아야 합니다.
  4. 토큰 엔드포인트로 코드를 교환해 응답 JSON 전체를 /root/oidc/token.json 에 저장합니다. client_id=labhub-web, client_secret=labhub-secret 을 함께 보냅니다. access_token, id_token, token_type 이 있어야 하고 token_typeBearer 입니다.
  5. id_token페이로드를 디코드해 /root/oidc/claims.json 에 저장합니다. iss, aud, sub, exp, nonce 가 있어야 하고, audlabhub-web, nonce 는 2단계에서 보낸 값과 같아야 합니다.
  6. /root/oidc/verify.sh 를 만듭니다. 인자 두 개(ID토큰 공개키PEM)를 받아 서명이 유효하면 종료코드 0, 아니면 0 이 아닌 값으로 끝냅니다. 공개키는 /opt/lab/fixtures/auth/oidc/idp-public.pem 에 있습니다.
  7. access_token 으로 userinfo 엔드포인트를 호출해 /root/oidc/userinfo.json 에 저장합니다. sub 값이 5단계 claims.jsonsub 와 같아야 합니다.
  8. /root/oidc/checklist.csv 를 만듭니다. 첫 줄은 item,risk. 서명, iss, aud, exp, nonce, alg 여섯 항목item 에 있어야 하고, risk 에는 그 항목을 검증하지 않으면 가능한 공격/사고를 10자 이상으로 적습니다.

참고

IdP 기동과 discovery 문서

실습용 IdP 를 기동합니다. python3 /opt/lab/fixtures/auth/oidc/idp.py 9000 (백그라운드) discovery 문서를 받아 /root/oidc/discovery.json 에 저장합니다. (http://127.0.0.1:9000/.well-known/openid-configuration) issuer, authorization_endpoint, token_endpoint, jwks_uri 가 있어야 합니다.

OIDC 제공자는 표준 경로에 설정 문서를 둡니다. 그 문서 하나로 엔드포인트 주소를 전부 알 수 있습니다. jq 로 필요한 값만 뽑아 보세요.

authorization URL 조립

/root/oidc/auth-url.txt 에 authorization URL 한 줄을 적습니다. 필수 파라미터: response_type=code, client_id=labhub-web, redirect_uri=http://127.0.0.1:9100/callback, scope=openid profile email, state=<16자 이상>, nonce=<16자 이상>.

필수 파라미터를 빠뜨리면 IdP 가 오류를 냅니다. state 와 nonce 는 역할이 다릅니다 - 하나는 CSRF 방지, 하나는 토큰 재생 방지입니다.

인가 코드 수신

그 URL 을 리다이렉트를 따라가지 않고 호출해 응답의 Location 헤더를 /root/oidc/callback.txt 에 저장하고, 거기서 code 값만 뽑아 /root/oidc/code.txt 에 저장합니다. Location 의 state 는 2단계에서 보낸 값과 같아야 합니다.

브라우저 없이도 리다이렉트 응답의 Location 헤더를 읽으면 코드를 볼 수 있습니다. curl 이 리다이렉트를 따라가지 않게 해야 합니다.

토큰 교환

토큰 엔드포인트로 코드를 교환해 응답 JSON 전체를 /root/oidc/token.json 에 저장합니다. client_id=labhub-web, client_secret=labhub-secret 을 함께 보냅니다. access_token, id_token, token_type 이 있어야 하고 token_typeBearer 입니다.

토큰 엔드포인트는 POST 이고 form 형식입니다. 인가 코드는 일회용이라 두 번 쓰면 실패합니다. 실패하면 2~3단계를 다시 하세요.

ID 토큰 페이로드 디코드

id_token페이로드를 디코드해 /root/oidc/claims.json 에 저장합니다. iss, aud, sub, exp, nonce 가 있어야 하고, audlabhub-web, nonce 는 2단계에서 보낸 값과 같아야 합니다.

JWT 는 점으로 나뉜 세 부분이고 각각 base64url 입니다. base64url 은 표준 base64 와 문자 두 개가 다르고 패딩이 없을 수 있습니다.

서명 검증 스크립트

/root/oidc/verify.sh 를 만듭니다. 인자 두 개(ID토큰 공개키PEM)를 받아 서명이 유효하면 종료코드 0, 아니면 0 이 아닌 값으로 끝냅니다. 공개키는 /opt/lab/fixtures/auth/oidc/idp-public.pem 에 있습니다.

서명 대상은 '헤더.페이로드' 문자열 전체입니다. openssl dgst 로 공개키 검증을 할 수 있고, 서명값은 base64url 디코딩이 필요합니다.

userinfo 호출

access_token 으로 userinfo 엔드포인트를 호출해 /root/oidc/userinfo.json 에 저장합니다. sub 값이 5단계 claims.jsonsub 와 같아야 합니다.

액세스 토큰은 Authorization 헤더에 Bearer 방식으로 보냅니다. 반환된 sub 가 ID 토큰의 sub 와 같은지 확인하는 것이 이 단계의 핵심입니다.

ID 토큰 검증 체크리스트

/root/oidc/checklist.csv 를 만듭니다. 첫 줄은 item,risk. 서명, iss, aud, exp, nonce, alg 여섯 항목item 에 있어야 하고, risk 에는 그 항목을 검증하지 않으면 가능한 공격/사고를 10자 이상으로 적습니다.

각 항목이 왜 필요한지가 아니라 '검증하지 않으면 무슨 공격이 가능한지'를 적으세요. 그래야 나중에 리뷰에서 설득력이 생깁니다.