적절하지 않은 난수 값 사용은 보안 취약점
예측 가능한 난수를 사용하는 것은 시스템에 보안약점을 유발한다.
Random은 정말 랜덤인거 아닌가?...
아니였다.
원인
- 컴퓨터의 난수발생기는 난수 값을 결정하는 시드(Seed) 값이 고정될 경우, 매번 동일한 난수값이 발생한다.
public class Main {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> System.out.println(getRandomValue(System.currentTimeMillis())));
Thread thread2 = new Thread(() -> System.out.println(getRandomValue(System.currentTimeMillis())));
Thread thread3 = new Thread(() -> System.out.println(getRandomValue(System.currentTimeMillis())));
Thread thread4 = new Thread(() -> System.out.println(getRandomValue(System.currentTimeMillis())));
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
public static long getRandomValue(long maxValue) {
Random random = new Random(10000);
return random.nextLong(maxValue);
}
}
간단한 예시를 그냥 만들어 보았는데,
시드 값이 고정될 경우 쓰레드 4개를 동시에 수행했을 경우 같은 값이 나온다는 뜻.!
보안 취약점 가이드 라인에서는 매번 변경되는 시드 값을 사용하라고 나와 있습니다.
Random random = new Random();
String authKey = Integer.toString(random.nextInt());
그러나, 이 조차 보안 결정을 위한 난수로는 안전하지 않다고 합니다.
해결책
보안 취약점 가이드에서는 SecureRandom이라는 클래스를 사용하도록 권장하고 있습니다.
Random은 시드(seed)의 크기를 48비트를 사용하는 반면, SecureRandom은 최대 128비트의 시드를 사용할 수 있습니다.
2^48 = 281조
VS
2^128 = ~~~~~~~엄청나게 큰 수
SecureRandom random = SecureRandom.getInstanceStrong();
getInstanceStrong을 사용했을 시에 사용되는 알고리즘은 현재 가지고 있는 암호화 알고리즘 중에 가장 강한 것을 선택해서 난수를 생성한다고 합니다.
SecureRandom.getInstanceStrong()
를 사용하게 되면 기본 설정으로 특정 경로에서 시드 값을 얻어옵니다.
JDK가 있는 폴더\conf\security를 찾아가 보면 있다해서 찾아보았습니다.
검색 검색~
- Windows-PRNG:SunMSCAPI
- Window 운영체제에서 Microsoft Cryptographic API(MSCAPI)를 사용하여 안전한 난수를 생성한다.
- 이 알고리즘은 Windows 환경에서만 사용 가능합니다.
- DRBG:SUN
- Deterministic Random Bit Generator (DRBG)를 통해 난수를 생성합니다.
- Java에서 제공하는 난수 생성 알고리즘 중 하나
public class Main {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> System.out.println(getRandomValue(System.currentTimeMillis())));
Thread thread2 = new Thread(() -> System.out.println(getRandomValue(System.currentTimeMillis())));
Thread thread3 = new Thread(() -> System.out.println(getRandomValue(System.currentTimeMillis())));
Thread thread4 = new Thread(() -> System.out.println(getRandomValue(System.currentTimeMillis())));
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
public static long getRandomValue(long maxValue) {
try {
SecureRandom random = SecureRandom.getInstanceStrong();
return random.nextLong(maxValue);
} catch (NoSuchAlgorithmException e) {
System.out.println(e.getMessage());
return -1;
}
}
}
- 간단하게 테스트를 진행해 보았고
아까와는 다른 결과를 볼 수 있었다.
여기서 SecureRandom은 무적인가? 생각할 수 있겠지만
특정 경로에서 알고리즘 파일을 읽어서 가져오는 시간이 존재하기 때문에
SecureRandom을 사용하면 성능이 저하되는 문제점을 가지고 있다고 한다.
참고한 블로그
너무너무 잘 정리해 주셨다.
https://madplay.github.io/post/java-random
https://kdhyo98.tistory.com/48
'프로그래밍 언어 > 자바' 카테고리의 다른 글
Checked, Unchecked Exception, printStackTrace (0) | 2024.04.10 |
---|---|
nextInt() 사용 후 nextLine()을 입력해줘야 하는 이유 (0) | 2024.04.07 |