회원가입시 본인인증을 하기 위해서 SMS 인증을 한다.
클라이언트 개발자 분들께 들어보니
SMS같은 경우는 API 호출 IP가 계속 달라지면 안돼서
서버에서 처리하는 게 좋다고 한다.
구현 방식은 간단하다.
SMS 서비스로 휴대폰에 인증번호를 보내고, 레디스에 유효시간동안 담아놓은 다음 인증을 처리한다.
자바의 Random 클래스는 선형 합동 생성기(linear congruential pseudorandom number generator)를 사용한다.
LCGS는 보안적인 목적으로는 쓰지 않는 게 좋다고 한다. LCGS로 만든 숫자는 예측가능(predictable)하기 때문이다.
The assumption that an attacker would have to wait for the LCG to repeat after a full cycle is wrong. Even with an optimal cycle (the modulus m in its recurrence relation) it is very easy to predict future values in much less time than a full cycle. After all, it's just a bunch of modular equations that need to be solved, which becomes easy as soon as you have observed enough output values of the LCG.
LCGS에는 일종의 싸이클이 있기 때문에, 처음 만들어진 숫자 2개만 알고 있어도 바로 예측이 가능하다고 한다.
그래서, SecureRandome클래스를 써서 예측이 더 어려운 방식으로 숫자를 생성할 필요가 있다.
Random uses the system clock as the seed/or to generate the seed. So they can be reproduced easily if the attacker knows the time at which the seed was generated. But SecureRandom takes Random Data from your os(they can be interval between keystrokes etc - most os collect these data store them in files - /dev/random and /dev/urandom in case of linux/solaris) and uses that as the seed.
So if the small token size is okay(in case of Random), you can continue using your code without any changes, since you are using SecureRandom to generate the seed. But if you want larger tokens(which cannot be subject to brute force attacks) go with SecureRandom -
In case of random just 2^48 attempts are required, with todays advanced cpu's it is possible to break it in practical time. But for securerandom 2^128 attempts will be required, which will take years and years to break even with today's advanced machines.
Go for SecureRandom - Use Native PRNG (as given in the link above) because it takes random values from the /dev/random file for each call to nextBytes(). This way an attacker observing the output will not be able to make out anything unless he is controlling the contents of the /dev/random file(which is very unlikely)
Random 클래스는 system clock(디폴트값)을 시드를 생성하고(그래서 해커가 시드가 생성된 시간만 알고 있으면 값을 쉽게 복제할 수 있다), SecureRandom은 OS의 랜덤 데이터를 사용한다. 그래서, Random은 해커가 쉽게 재생산할 수 있지만, SecureRandom는 아니라고 한다.
또한, Random은 48비트형식이고, securerandom는 128비트다. 최근의 cpu가 random을 해독하는 게 그렇게 많은 시간이 걸리지 않는 반면, securerandom은 수년에 걸릴 수 있다고 한다.
@Service
public class SmsServiceV1 {
private String generateRandomNumber() {
SecureRandom random = new SecureRandom();
StringBuilder randomNum = new StringBuilder();
for (int i = 0; i < 6; i++) {
randomNum.append(random.nextInt(10));
}
return randomNum.toString();
}
}
이렇게만 해주면 된다!
참고자료
Difference between java.util.Random and java.security.SecureRandom