예측 가능한 시드로 보안 난수 초기화

Predictable Seed in PRNG

설명

SecureRandom 같은 보안 난수 생성기에 시스템 시간, 고정 바이트 배열 등 예측 가능한 seed를 주입하면 난수 출력이 예측 가능해집니다. 공격자는 요청 시각 범위를 추정하거나 알려진 상수 seed로 동일한 PRNG 상태를 재현해 세션 ID, 토큰, OTP 등을 맞출 수 있습니다. 이는 OWASP A02: Cryptographic Failures와 연관되며, 특히 시간 기반 seed(System.currentTimeMillis, nanoTime), 문자열.getBytes(), new byte[] 리터럴 사용 시 위험합니다.

잠재적 영향

  • 인증/세션 탈취: 예측 가능한 토큰이나 세션 ID를 추측해 다른 사용자의 세션을 가로챌 수 있습니다.

  • 권한 오용/가짜 요청: CSRF 토큰, API 키 유사 토큰을 예측해 권한 있는 요청을 위조할 수 있습니다.

  • 일회용 코드(OTP) 예측: 비밀번호 재설정 코드나 2차 인증 코드가 추측 가능해집니다.

  • 무차별 대입 범위 축소: 시간 기반 seed로 탐색 공간이 크게 줄어 공격 성공 가능성이 높아집니다.

해결 방법

  • seed를 명시적으로 설정하지 않기: new SecureRandom()만 사용해 OS 엔트로피로 자동 초기화되도록 합니다. setSeed(System.currentTimeMillis()), 문자열.getBytes(), new byte[]{...} 금지.

  • (불가피할 경우) 예측 불가능한 seed 사용: new SecureRandom().generateSeed(n)처럼 충분히 랜덤한 바이트를 사용합니다. 단, 필요 이상으로 setSeed 호출하지 말고 기본 초기화에 의존하세요.

  • 보안이 중요하지 않은 용도는 Random 사용 고려: 성능이 중요하고 예측 불가능성이 필요 없다면 java.util.Random을 쓰되, 보안 토큰/세션/OTP에는 절대 사용하지 않습니다.

  • 토큰 설계 보강: 충분한 길이(예: ≥128비트), Base64 인코딩 사용, 만료 시간 부여 및 재사용 금지.

  • 키/암호용 재료는 전용 API 사용: 암호 키는 KeyGenerator, PBKDF2 등 표준 Key Derivation 사용.

취약한 코드 및 안전한 코드 예시

취약한 코드

안전한 코드

설명:

  • 취약한 코드: System.currentTimeMillis()는 요청 시각을 기준으로 쉽게 추정 가능합니다. 공격자는 가능한 시간 창을 대입해 동일한 PRNG 상태를 재현하고 토큰을 예측할 수 있습니다. 따라서 시간/상수 기반 seed는 보안 난수 용도에 부적절합니다.

  • 안전한 코드: SecureRandom을 seed 없이 생성하면 운영체제 엔트로피로 안전하게 초기화됩니다. 충분한 길이의 바이트를 생성해 Base64로 인코딩하면 예측 가능성이 낮아집니다. seed를 반드시 지정해야 하는 경우에도 generateSeed로 얻은 고품질 랜덤 바이트를 사용해 예측을 어렵게 합니다.

참조

Last updated