본문 바로가기

Backend/Java

자바 비밀번호 암호화 (SHA256,SHA512) + Salt

SHA (Secure Hash Algorithm, 안전한 해시 알고리즘)은 해시 함수들의 모음이라고 보면 되요.

복호화가 불가능한 단방향 암호화 기법으로 데이터를 안전하게 저장할 수 있습니다.

SHA256과 SHA512도 그 중 하나이며 가장 많이 쓰이는 함수이므로 구현해보도록 할게요.

SHA256

String raw = "1111";
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(raw.getBytes());
String hex = String.format("%064x", new BigInteger(1, md.digest()));

 

SHA512

String raw = "1111";
MessageDigest md = MessageDigest.getInstance("SHA-512");
md.update(raw.getBytes());
String hex = String.format("%0128x", new BigInteger(1, md.digest()));

 

 

 

레인보우 테이블

원본-해쉬 쌍을 무진장 저장해놓은 테이블이에요.

이 테이블의 등장으로 해커가 암호화된 데이터가 무엇인지 알아내는데에 많은 시간이 걸리지 않게 되었어요.

지금 이 시간에도 레인보우 테이블에는 수많은 해시값이 쌓이고 있을거에요.

Salt

레인보우 테이블과 같은 해커의 공격으로부터 쉽게 무너지지 않도록 하는 보안 대책이에요.

평문과 salt(무작위 랜덤 문자열)을 합친 후에 암호화하는 방식입니다.

길이가 훨씬 길어져서 레인보우 테이블에서 데이터를 확보하려면 훨씬 더 방대한 시간이 필요해요.

 

아래 코드는 평문과 Salt를 더하여 SHA256으로 암호화하였습니다.

SHA512로 할 경우에 위의 코드를 참고하여 수정하면 되요.

 

String raw = "1111";

SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
byte[] bytes = new byte[16];
random.nextBytes(bytes);
String salt = new String(Base64.getEncoder().encode(bytes));

MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(salt.getBytes());
md.update(raw.getBytes());
String hex = String.format("%064x", new BigInteger(1, md.digest()));

 

 

 

 

똑같이 1111이라는 문자를 암호화하였는데 salt 값 때문에 각기 다른 해시값이 생성됨을 알 수 있어요.

salt는 별도로 연관지어 저장하거나, 생성된 해시값 앞에 붙이기도 해요.

동일값임을 비교

로그인을 예시로 들어볼게요.

우선 평문 비밀번호 + 무작위로 생성된 salt 값으로 암호화한 비밀번호를 만들어요.

암호화한 비밀번호와 salt 값을 로그인 아이디와 함께 DB에 저장합니다.

그 후에 로그인 시도하면 로그인 아이디로 salt 값을 조회해서 요청온 비밀번호와 salt 값을 더하여 암호화한 후 비교합니다.

지금 다룬 암호화 알고리즘 수준으로는 이 방법이 한계입니다...

 

그래서 어떻게 salt를 활용할지 모르시겠다면 bcrypt를 사용하시는 것을 추천해드립니다.

오로지 평문과 암호화 문자열만으로 비교하는 메서드를 사용할 수 있습니다.

bcrypt 함수의 알고리즘이 궁금하시다면 따로 찾아보시길 추천드립니다. (저는 알고리즘 모르고 그냥 사용하고 있습니다... ㅠㅠ)