홈 › 인증·로그인 › 03 / 3

3단계: 2FA(TOTP) 와 로그인 흐름 통합

섹션 7진행 0 / 3

7. 정리

  • TOTP 는 HMAC-SHA1(시크릿, 시각/30) 의 동적 절단 mod 10^6 입니다. 서버와 앱이 시크릿과 시계만 공유하면 통신 없이 같은 6자리가 나옵니다. RFC 6238 부록 B 벡터로 구현을 검증하세요.
  • 시크릿은 Base32 + otpauth URI 로 QR 에 실어 한 번만 넘기고, 반드시 코드 1회 검증(confirm) 후 활성화합니다. 서버에는 암호화해 저장합니다.
  • ±1 스텝 윈도우 + 마지막 성공 스텝 저장이 짝입니다. 윈도우만 있으면 90초간 재생이 되고, 재생 방지만 있으면 시계 오차에 로그인이 안 됩니다.
  • 백업 코드는 해시만 저장하는 1회용 비밀번호입니다. 실패 카운터는 TOTP 와 합쳐 5회 잠금을 겁니다.
  • 통합 흐름의 핵심은 mfa_token 입니다. aud=mfa·3분·jti 1회용으로 "비밀번호만 통과한 상태" 를 격리하면 기존 aud 검사 하나로 API 접근이 막힙니다. 최종 Access 의 amr 에 통과 요소를 기록해 회전 후에도 유지하고 step-up 인가에 씁니다.
  • Spring Security 에서 2FA 는 인가 단계에 끼어듭니다. 비밀번호 통과 = 권한 부족한 Authentication, 코드 통과 = 권한 교체. 임직원은 SAML IdP 가 MFA 를 맡고 AuthnContextClassRef 를 amr 로 옮기며, 로컬 계정만 우리 TOTP 를 탑니다.

인증·로그인 레벨 마무리. 1단계에서 비밀번호 해시와 JWT 서명을, 2단계에서 토큰의 수명·회전·폐기와 OAuth2 위임을, 3단계에서 두 번째 요소와 통합을 다뤘습니다.

세 단계의 소스는 같은 Jwt·PasswordHasher·TokenService 를 이어 쓰므로 한 프로젝트로 합치면 그대로 로그인 서버의 뼈대가 됩니다.

실무로 옮길 때는 순서대로 PasswordEncoder → spring-security-oauth2-resource-server + jjwt → 인가 규칙(authorizeHttpRequests) 에 대응시킵니다. 이 레슨들이 직접 구현한 검사 항목(aud, jti, lastUsedStep, 실패 잠금)이 라이브러리 설정 어디에 해당하는지 하나씩 확인하는 것이 가장 빠른 길입니다.