복구 코드… 아니면 하나의 복구 코드?

발행: (2026년 2월 12일 오후 05:08 GMT+9)
5 분 소요
원문: Dev.to

Source: Dev.to

Overview

인증 논의는 보통 다음에 초점을 맞춥니다:

  • Passkeys
  • TOTP
  • 하드웨어 토큰
  • 패스워드리스

복구 메커니즘은 같은 수준의 분석이 거의 이루어지지 않지만, 복구가 실제 보안 경계를 정의합니다. 로그인은 강력하지만 복구가 약하면 시스템 전체가 약합니다.

Backup Code Lists (5–10 one‑time codes)

Properties

  • 여러 개의 정적 토큰
  • 일회용 사용
  • 재생성 가능한 리스트

Typical Issues

  • 사용자가 제대로 보관하지 않음
  • 스크린샷이 찍힘
  • 코드가 잊혀짐
  • 엔트로피 분석이 이루어지지 않음
  • “코드가 많다”는 이유만으로 보안이 있다고 가정함

Security Considerations

  • 실제 중요한 것은 엔트로피입니다.
  • 복구는 위임된 인증이 됩니다.
  • 보안은 다음에 의존합니다:
    • 이메일 계정 보호
    • SIM 보안
    • 외부 공격 표면

이는 위협 모델을 바꾸는 것이지 강화하는 것이 아닙니다.

Seed Phrases (12–24 words)

Characteristics

  • 개인 키 복구
  • 높은 엔트로피
  • 오프라인 저장 기대

Usability

  • 암호학적으로 엄격하지만 사용성 비용이 높음.

Assumptions

  • 공격자가 복구 엔드포인트에 접근 가능
  • 데이터 유출 없음
  • 내부 침해 없음
  • 공격은 순수히 온라인에서만 발생

Security Depends On

  • 엔트로피
  • 생성 품질
  • 속도 제한

발행된 코드 수에 의존하지 않습니다.

Tested Configuration

  • Length: 15 characters
  • Alphabet size: 31 symbols (ambiguous characters such as 0/O and 1/I/L excluded)
  • Generation: CSPRNG (crypto.randomBytes) with rejection sampling (no modulo bias)
  • TTL: No fixed TTL
  • Rate limiting: Strict; a few attempts within several minutes
  • Rotation: Automatic after successful use

Entropy Calculation

  • Alphabet size: 31
  • Total search space: (31^{15})
  • Entropy: ≈ 78 bits

Aggressive Attack Scenario

  • Attempts: ~1.5 million per year
  • Probability of success: Negligible (effectively infeasible for an online attack)

10개의 코드를 발행한다고 해서 단일 시도에 대한 엔트로피가 곱해지는 것이 아니라, 공격자는 여전히 하나씩 유효한 코드를 추측합니다.

Security Depends On

  • 계정당 속도 제한
  • 식별자당 스로틀링
  • 코드당 엔트로피
  • 올바른 무작위 생성
  • 안전한 저장 모델

사용자에게 제공되는 출력 가능한 토큰 수에 의존하지 않습니다.

Randomness

// Use a cryptographically secure PRNG
const crypto = require('crypto');
function generateCode(length, alphabet) {
  const bytes = crypto.randomBytes(length * 2); // oversample
  let result = '';
  let i = 0;
  while (result.length < length && i < bytes.length) {
    const idx = bytes[i] % alphabet.length;
    // Rejection sampling to avoid modulo bias
    if (bytes[i] < 256 - (256 % alphabet.length)) {
      result += alphabet[idx];
    }
    i++;
  }
  return result;
}
  • Math.random() 사용을 피하세요.
  • 바이트를 알파벳에 매핑할 때 모듈로 바이어스를 없애기 위해 거부 샘플링을 사용하세요.

Rate Limiting

Critical Points

  • 복구 식별자당 제한 (IP만이 아니라).
  • 계정당 및 IP당 제한을 결합.
  • 필요하면 지수 백오프를 추가.

Rotation

복구가 성공한 후:

  1. 이전 코드를 무효화한다.
  2. 새 코드를 생성한다.
  3. 장기 정적 토큰을 피한다.

Conclusion

복구는 UX에 대한 사후 생각이 아니라 인증 원시 요소입니다. 복구 엔트로피와 시도 제어가 제대로 설계된다면, 단일 복구 코드만으로도 온라인 위협 모델 하에서 충분히 안전할 수 있습니다.

진정한 질문은 **“코드가 몇 개인가?”**가 아니라 “엔트로피는 얼마이며 공격 표면을 어떻게 제어하고 있는가?” 입니다.

0 조회
Back to Blog

관련 글

더 보기 »