Modulo Bias로 인한 안전하지 않은 암호화 알고리즘

Biased Cryptographic Randomness (Modulo Bias)

설명

암호화 알고리즘을 통해 생성한 안전한 난수에서 나온 값을 단순히 % (모듈로) 연산 등으로 특정 범위로 줄이면, 범위가 원래 난수 공간으로 딱 나누어떨어지지 않는 경우 값의 분포가 고르지 않게 됩니다. 이를 modulo bias라고 하며, 일부 값이 다른 값보다 더 자주 나오게 됩니다. 공격자는 이 bias로 토큰·코드·식별자의 예측 난이도를 낮추어 추측(브루트포스)의 성공 확률을 높이거나, 충돌/중복을 유도하여 보안을 약화시킬 수 있습니다.

잠재적 영향

  • 인증/토큰 예측 가능성 증가: 패스워드 재설정 토큰, 세션 ID, OTP 등에서 특정 값이 더 자주 나와 추측 성공률이 상승합니다.

  • 키 공간 축소: 균등 분포가 깨지면서 실질 탐색 공간이 줄어들어 브루트포스 공격이 더 빨라집니다.

  • 인증 우회/권한 상승: 예측 가능한 CSRF 토큰·초대 코드·가입 코드 등을 노려 계정 탈취나 권한 오용이 발생할 수 있습니다.

  • 충돌 및 중복 증가: 인증 코드나 쿠폰 코드의 중복 발생 가능성이 높아져 재사용·사기·서비스 남용 위험이 커집니다.

해결 방법

  • 암호학적 난수에 직접 % (모듈로) 등 축소 연산을 적용하지 마세요.

  • Node.js에서는 crypto.randomInt()처럼 bias을 제거한 API를 사용하세요.

  • 반드시 수학적으로 범위를 줄여야 한다면 거절 표본추출(rejection sampling)을 사용해 균등 분포 범위 밖의 값을 버리세요.

  • 문자열 토큰은 검증된 라이브러리(예: crypto-random-string) 또는 충분히 큰 바이트를 그대로 안전한 인코딩(hex/base64url 등)으로 변환해 사용하세요.

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

취약한 코드

안전한 코드

설명:

  • 취약한 코드: 난수(0..2^32-1)를 1,000,000으로 나눈 나머지를 쓰면, 2^32가 1,000,000으로 나누어떨어지지 않기 때문에 일부 값이 더 자주 나옵니다. 이 bias은 공격자가 특정 코드/토큰을 더 높은 확률로 맞출 수 있게 만들어 예측 가능성을 키웁니다.

  • 안전한 코드: crypto.randomInt()는 내부적으로 bias을 제거하여 지정 범위 내 균등 분포를 보장합니다. 거절 표본추출 방식은 범위를 균등하게 나눌 수 있는 상한(max) 밖의 난수는 버린 뒤 나머지를 취하여 동일한 확률로 값을 생성하므로 bias이 제거됩니다.

참조

Last updated