들어가며
Math.random()에서 보안취약점이 걸려 코드를 수정해야 하는 일이 생겼다. 찾아보니 Math.random()은 완전 랜덤 값을 생성하지 않는다고 한다.
Math.random()
- javaScript에서 0 이상 1 미만 (0 <= x < 1)의 난수를 반환하는 함수이다.
- 같은 값을 반복하지 않지만, 내부적으로 의사 난수 생성기(PRNG, Pseudorandom Number Generator)를 사용하기 때문에 완전 랜덤 값은 아니다.
보안 취약점
1. 예측 가능한 난수 생성 (Deterministic)
Math.random()은 랜덤한 수를 생성하는 것처럼 보이지만 사실 의사 난수 생성기(PRNG)를 기반으로 동작하는, 특정 알고리즘을 통해 계산된 값이다. 브라우저마다 Math.random()의 구현 방식은 다를 수 있지만, 대부분 기존의 내부 상태를 기반으로 난수를 생성한다. 내부 상태가 노출되거나, 일정한 패턴이 있으면 난수 예측이 가능해진다. 실제로 지난 2013년, 온라인 도박 사이트에서 javaScript의 Math.random()을 사용해 카드 덱을 섞었는데, 공격자가 패턴을 분석해 다음 카드가 무엇인지 예측하여 돈을 따간 사례가 있다고 한다.
2. 시드 (seed) 제어 불가능
보안성이 강한 난수 생성기는 초기 값(Seed)이 예측 불가능한 방식으로 설정되어야 하지만, Math.random()은 개발자가 직접 시드를 제어할 수 없고, 내부적으로 브라우저가 시드를 관리한다. 만약 브라우저에서 같은 시드 값을 사용했다면, Math.random()은 같은 난수를 반복적으로 생성할 가능성이 있으며, 일부 환경에서는 시간 기반 시드를 사용하기 때문에 특정 시간에 생성된 난수를 예측할 수 있다. 공격자가 어떤 환경에서 실행되는지 알고 있다면, 해당 환경의 Math.random() 패턴을 학습하고 시드 값을 추정해, 생성될 난수를 예측할 수 있는 것이다.
3. 암호학적 용도로 부적합
비밀번호, API 키, 인증 토큰 등 보안이 필요한 용도에서는 사용하지 않아야 한다.
해결방안
crypto.randomBytes() 사용 (Node.js 환경)
암호학적으로 안전한 난수를 제공하므로 토큰, 비밀번호, 세션 키 등에 적합하다고 한다.
예제 1
const crypto = require("crypto");
function generateSecureToken() {
return crypto.randomBytes(16).toString("hex");
}
💡 HTTP 환경에서는?
HTTP 환경, 제한된 웹뷰, 일부 보안이 취약한 환경에서는 crypto 기능이 제한될 수 있다. 나는 HTTP 환경이라 crypto 모듈을 사용할 수 없어 Date.now()를 사용해 밀리초 단위의 현재 시간을 반환하는 방식을 사용했다. 패턴 유추가 가능해 안전한 방식은 아니지만 새로고침할 때마다 색상을 다르게 표현할 목적이었기 때문에 보안과 상관없다.
Before
const colorPalettes = [
["#FFBE0B", "#FB5607", "#FF006E", "#8338EC", "#3A86FF"],
["#F72585", "#7209B7", "#3A0CA3", "#4361EE", "#4CC9F0"],
// 생략
];
function getRandomColors(){
const randomIndex = Math.floor(Math.random() * colorPalettes.length);
return colorPalettes[randomIndex];
}
After
const colorPalettes = [
["#FFBE0B", "#FB5607", "#FF006E", "#8338EC", "#3A86FF"],
["#F72585", "#7209B7", "#3A0CA3", "#4361EE", "#4CC9F0"],
// 생략
];
function getRandomColors(){
const randomIdx = Math.floor(Date.now() % colorPalettes.length); // 바뀐 부분
return colorPalettes[randomIdx];
}
참고
'Language > JavaScript' 카테고리의 다른 글
[JS] Symbol 타입 필요성 (0) | 2025.03.14 |
---|---|
[JS] forEach(console.log) (0) | 2025.03.02 |