자바의 난수생성기 Random, SecureRandom

8249 단어 JavaprojectJava

이메일로 임시비밀번호를 전송하려고할때, 난수를 생성하여 전달해주려고하던찰나에 궁금증이생겼다.
학부시절에 처음 난수를생성할때 Random함수를 가끔 썼던거같은데 이번에 SecureRandom 에대해 알게되었다.

왜 Random은 암호학적으로 안전하지않은가

https://docs.oracle.com/javase/8/docs/api/java/util/Random.html

java.util.Random의 인스턴스는 암호학적으로 안전하지 않습니다.
보안에 민감한 응용 프로그램에서 사용할 암호학적으로 안전한 의사 난수 생성기를 얻으려면 SecureRandom을 대신 사용하는 것이 좋습니다.

Random함수는 난수를 생성하긴한다.
그러나 진짜 난수가 생성되는게아니라, 난수처럼 보이는 알고리즘을 통한 규칙적인 난수를 생성하는것이다.

컴퓨터는 사람과 달리 무의식적인 선택, 또는 우연에 의하는 선택을 할 수 없기에 기본적으로 정해진 입력에 따라 정해진 값만 낼수있다.
흔히 보는 랜덤은 정말로 임의의 값이 아니고 특정한 방법으로 여러 계산 과정을 거쳐 사람이 볼 때에 마치 임의의 값인 것처럼 보이게 하는 것이다. '의사난수(Pseudo Random)'라고 한다.
이를 해결하기 위하는 방법은 난수표를 여러 개 만들어 놓고 매번 다른 난수표를 읽히는 것이다.
이 난수표를 선택하는 것을 '시드'라고 한다. 그런데 시드값이 똑같으면 선택되는 난수표도 똑같기 때문에 시드값도 난수여야 한다. 즉, 난수를 만들려면 난수가 필요한 문제가 발생하는 것.

https://namu.wiki/w/%EB%82%9C%EC%88%98%EC%83%9D%EC%84%B1

즉, 기준이 되는값을 세팅해주고 난수인것처럼 보이는 랜덤의값을 보여주는것 같지만
시드값이 동일하면 매번같은값을 보여주는것이다.

    @Test
    @DisplayName("Random함수 테스트")
    void randomTest() {
        int i = 0;
        while (i < 3) {
            Random random = new Random(10);
            for (int j = 0; j < 5; j++) System.out.println(random.nextDouble());
            i++;
        }
    }

반복되는 패턴이 보일것이다. 정확한 랜덤이 아니다.
이를해결하기위해서, Seed값을 시간으로 지정하는것이 기본값이지만 공격자가 시드 생성시간을 알고있으면
위험할수있다.

ThreadLocalRandom

Random함수는 멀티쓰레드환경에서 동시요청이 들어와도 같은 난수를 반환하진않는다.
그러나 스레드간 동일한 인스턴스를 동시에 사용하면 경합이 발생하여
엄청난 성능저하를 일으킨다.

ThreadLocalRandom은 Random에비해 오버헤드와 경합이 훨씬적지만
Random과 마찬가지로 암호학적으로 안전하지않다.

SecureRandom

  • SecureRandom은 48비트만 있는 Random함수와 달리 최대 128비트를 포함할수있기때문에
    반복할가능성이 더적다.
  • OS에서 임의의데이터를 가져온다
    -> ex) /dev/random 와같은 유사난수 생성역할을 하는 파일을 사용한다.
  • FIPS 140-2(암호학에서 사용되는 생성기표준) 에서 지정한 테스트를 준수하기때문에 좀더 안전하다
  • 조금더 안전한 알고리즘을 구현한다 (SHA1PRNG)
   @Test
    @DisplayName("SecureRandom함수 테스트")
    void secureRandomTest() throws NoSuchAlgorithmException {
        int i = 0;
        while (i < 3) {
            SecureRandom random = SecureRandom.getInstanceStrong();
            //  getInstanceStrong() : 보안속성에 지정된 알고리즘을 사용하여 SecureRandom 객체를 반환한다.
            for (int j = 0; j < 5; j++) System.out.printf("%.5f  ", random.nextDouble());
            i++;
            System.out.println();
        }
    }

thread-safe

자바7부터 내부적으로 동기화되어 명시적으로 스레드안전성을 보장한다.

references:
https://docs.oracle.com/javase/8/docs/api/java/util/Random.html
https://docs.oracle.com/javase/8/docs/api/java/security/SecureRandom.html
https://withseungryu.tistory.com/1
https://kdhyo98.tistory.com/m/48

좋은 웹페이지 즐겨찾기