프로젝트를 진행하면서 이용권 기능이 필요했습니다. 때문에 이용권에 맞게 난수 생성이 필요했고 안전한 난수를 어떻게 생성 할 수 있을까? 찾던 중에 SecureRandom 을 발견했습니다. 많이 들 사용하는 단순 Random의 경우 현재 시간을 시드로 사용하기 때문에 완벽한 무작위가 아닌 '의사난수' 가 생성 되기 때문에 목적에 부합하지 않았습니다. 그렇게 검색 도중 의사 난수가 아닌 확실하고 안전한 난수 생성을 도와주는 SecureRandom을 발견 하게 되었습니다. 이러한 SecureRandom 을 사용하면서 발생했던 이슈를 공유 해보려고 합니다.
SecureRadom는 어떻게 난수를 생성 할까?
시스템 시간을 시드로 해서 난수(?)를 생성하는 Random과 달리 OS에서 임의 데이터를 가져와서 시드를 생성한다고 합니다. 가져오는 경로는 주로 " / dev / random 및 / dev / urandom " 입니다.
난수 생성 하기
아래는 기본 SecureRadom 사용방법입니다. 단수히 SecureRadom을 얻어오고 해당 기능을 사용해서 랜덤한 숫자를 얻어 오는 로직입니다. SecureRadom을 얻어오는데 오류가 없다면 아래에 표시한 주석까지 도달을 하겠죠?
try {
SecureRandom secureRandom = SecureRandom.getInstanceStrong();
int i = secureRandom.nextInt(10);
// 여기 영역까지 도달 할 수 있을까요?
} catch (NoSuchAlgorithmException se){
}
정답은 도달하지 않습니다....
저의 경우에는 Local에서 동작할 경우에는 전혀 문제 없이 동작을 했습니다. 하지만 서버에 올려서 요청시 주석 부분까지 도달하지 않고 Freeze 걸렸습니다. 왜일까요? 문제는 "SecureRandom.getInstanceStrong()" 이었습니다. 그러면 이게 왜 문제를 일으킬까요?
SecureRandom.getInstanceStrong()
강력한(Secure) 난수 생성기를 초기화하는 과정에서 충분한 엔트로피(entropy)를 수집하기 위해 시스템 자원을 기다리기 때문입니다. 엔트로피는 난수생성의 품질을 결정하게 되는데 시스템의 키보드 입력, 마우스 움직임, 디스크 I/0 여러 소스에서 수집이 됩니다. 일반적으로 리눅스 시스템에서는 "/dev/random"은 엔트로피 풀에 충분한 크기의 데이터가 없다면 즉 부족하면 블록,프리징이 발생할 수 있다고 합니다. 때문에 저의 경우 주석 부분까지 도달 하지 못 하고 멈춰 있는 상태로 유지하다가 DB Connection이 끊기고 Exception 터져 버린 것입니다.
그러면 이걸 어떻게 해결 할 수 있을까요? 여러가지가 존재하지만 3가지만 간단하게 설명하겠습니다.
1. 가장 기본적인 난수생서기를 사용하는 new SecureRandom() 입니다. (단, 안전하지는 않습니다.)
SecureRandom secureRandom = new SecureRandom();
int i = secureRandom.nextInt(10);
2. 명시적으로 SHA1PRNG 알고리즘을 사용하는 난수 생성기를 생성하는 방법입니다. (1번 보다 안정적)
try {
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG")
int i = secureRandom.nextInt(10);
} catch (NoSuchAlgorithmException se){
}
3. securerandom.source=file:/dev/urandom 설정하기(오라클 가이드)
저의 경우에는 이용권에 초점이 맞춰져있어서 보안 보다는 성능으로 빠르게 난수 생성이 중요했기 때문에 "new SecureRandom()" 으로 해결 하고 중복여부를 체크하는 쪽에 초점을 맞추었습니다. 처음에는 계속 프르징이 발생하길래 커넥션 문제인줄 알았습니다. local에서는 정상 작동하고 서버에만 문제가 터지니 커넥션 설정관련 문제인가 싶었는데 로깅을 열심히 해 보고 많은 삽질을 해서 발견했습니다. 저와 동일 한 문제를 마주 하신 분들에게 도움이 되었으면 합니다.
https://madplay.github.io/post/java-random
'Spring boot' 카테고리의 다른 글
[Spring-boot] Mattermost Bot 사용 (0) | 2024.04.24 |
---|---|
Spring-boot Enum으로 Request,Response 받기 (0) | 2022.12.19 |
Spring boot - Transaction Propagation (1) | 2022.07.15 |
spring boot - 트랜잭션 (0) | 2022.07.01 |
Spring boot - Docker를 이용한 JENKINS 설치 (0) | 2022.06.28 |