기반 프리미티브
이 시스템 전체가 딛고 있는 바닥으로, 출처와 사용법 양쪽에서 실패할 수 있습니다.
규격 재현과 공격 거부를 이 페이지에서 직접 실행해 확인할 수 있습니다.
IV, salt, challenge 토큰, 세션 토큰, PKCE verifier가 모두 난수에서 나옵니다. 다른 모듈이 아무리 정확해도 난수가 예측 가능하면 전부 무너지므로 난수는 구현 세부가 아니라 독립된 계약입니다. 실패는 잘못된 출처와 잘못된 사용 두 갈래로 나타나며, 후자는 올바른 생성기를 쓰고도 발생합니다.
내부 상태를 관찰해도 다음 값을 계산할 수 없는 생성기만 토큰과 키에 사용합니다.
토큰 길이를 비트 단위로 따져 추측 비용이 충분한지 판단합니다.
범위로 접을 때 나머지 연산을 쓰면 분포가 균등하지 않아 추측 비용이 낮아집니다.
Math.random()은 통계적으로 균등하게 보이도록 설계됐을 뿐 예측 불가능하도록 설계되지 않았습니다. 내부 상태가 있고, 출력 몇 개를 관찰하면 그 상태를 복원해 이후 값을 전부 계산할 수 있습니다. 예측 가능한 토큰은 토큰이 아니므로 이 시스템의 어떤 경로에서도 사용하지 않습니다.
randomBytes(1)[0] % 10은 흔한 실수입니다. 0~255를 10으로 나눈 나머지는 균등하지 않아 0~5는 26번, 6~9는 25번 나옵니다. 통계가 아니라 산술의 문제라 전수 열거로 확인할 수 있고, 증명이 실제로 그렇게 합니다. 해법은 나눠 접는 대신 범위를 벗어난 값을 버리고 다시 뽑는 것(거부 표집)이며 randomInt가 이 방식을 씁니다.
16진수 32자와 base64url 32자는 길이가 같아 보이지만 각각 128비트와 192비트를 담습니다. 표현 방식이 아니라 원본 바이트 수가 추측 비용을 정하므로, 이 모듈은 토큰에 최소 128비트를 요구하고 그보다 짧으면 생성 자체를 거부합니다.
아래 증명은 설명이 아니라 실제 실행입니다. 버튼을 누르면 이 서버에서 지금 계산합니다.
엔트로피는 문자열 길이가 아니라 원본 바이트 수가 정한다 — 16진수 32자와 base64url 32자는 길이가 같아 보여도 담는 비트가 다르다. 이 모듈은 토큰에 128비트 하한을 걸고 그보다 짧으면 생성 자체를 거부한다.
표준이 고정한 test vector 를 그대로 실행합니다.
올바른 생성기를 써도 범위로 접는 방법이 틀리면 편향이 생긴다. randomBytes(1)[0] % 10은 0~5를 26번, 6~9를 25번 낸다 — 통계가 아니라 산술이라 전수 열거로 확인된다. 해법은 나눠 접는 대신 벗어난 값을 버리고 다시 뽑는 것이다.
막아야 할 입력을 실제로 넣고 거부되는지 확인합니다.
규격 원문을 우선합니다. 사례는 이 주제가 실제로 어떻게 뚫렸는지를 다룬 자료입니다.
엔트로피 출처와 흔한 오용을 정리한 문서.
결정론적 난수 생성기의 요구사항.
엔트로피 원을 줄인 한 줄 패치로 키 공간이 32,768개로 축소된 사례.
Next step
컨테이너 초기 부팅처럼 엔트로피가 부족할 수 있는 구간에서 생성기 가용성을 점검합니다.