취약한 난수 사용 (Insecure Randomness)

Insecure Randomness

설명

보안 민감한 값(세션 ID, 토큰, 임시 비밀번호 등)을 생성할 때 java.util.Random, Math.random(), ThreadLocalRandom, SplittableRandom 같은 암호학적으로 안전하지 않은 PRNG를 사용하면 값이 예측될 수 있습니다. 약한 PRNG는 시드와 내부 상태가 비교적 쉽게 추정되어 다음 출력이 유추될 수 있습니다. 공격자는 관측 가능한 일부 값(쿠키, 링크의 토큰 등)을 기반으로 이후 값을 계산하거나 무차별 대입으로 빠르게 맞춰 세션 탈취, 계정 탈취 등을 시도할 수 있습니다.

잠재적 영향

  • 세션 하이재킹: 예측 가능한 세션 ID/쿠키 값을 추측해 합법 사용자로 가장할 수 있습니다.

  • 계정 탈취: 임시 비밀번호, 로그인 토큰, 이메일 인증 토큰 등을 맞춰 계정을 장악할 수 있습니다.

  • 권한 남용/상승: 접근 토큰이나 API 키가 추정되면 권한 범위를 넘어선 행위를 수행할 수 있습니다.

  • CSRF 우회: 예측 가능한 CSRF 토큰으로 위조 요청을 성공시킬 수 있습니다.

  • 개인정보 유출: 인증·인가가 우회되면서 민감 데이터 접근이 가능해집니다.

해결 방법

  • 보안 용도에는 반드시 java.security.SecureRandom 사용

    • 예) SecureRandom sr = new SecureRandom(); byte[] b = new byte[32]; sr.nextBytes(b);

  • 약한 PRNG(Random, Math.random(), ThreadLocalRandom, SplittableRandom)를 세션/토큰/코드 등 보안값 생성에 사용하지 않기

  • 시드 고정 금지: new SecureRandom() 기본 엔트로피 사용, 직접 고정 시드 사용 금지

  • 충분한 엔트로피 확보: 최소 128비트 이상(권장 192~256비트) 랜덤 바이트 생성 후 Base64(URL-safe) 인코딩

  • 토큰 수명 제한 및 1회성 사용: 비밀번호 재설정/이메일 인증 토큰은 짧은 만료시간과 1회 사용 정책 적용

  • 서버 측 검증 강화: 추측 시도를 탐지하기 위한 속도 제한(rate limiting) 및 실패 횟수 제한 적용

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

취약한 코드

안전한 코드

설명:

  • 취약한 코드: ThreadLocalRandom은 성능 최적화용 PRNG로, 보안 목적에 필요한 예측 불가능성을 제공하지 않습니다. 이렇게 생성한 쿠키 값은 추정 또는 빠른 무차별 대입으로 맞춰질 가능성이 있어 세션 탈취로 이어질 수 있습니다.

  • 안전한 코드: SecureRandom은 CSPRNG로 충분한 엔트로피와 예측 불가능성을 제공합니다. 넉넉한 길이(256비트)의 난수를 생성해 URL-safe Base64로 인코딩하고, 고정 시드를 사용하지 않아 추측이 사실상 불가능합니다.

참조

Last updated