🧐 SHA-256
SHA-256은 Secure Hash Algorithm의 한 종류로서 256비트로 구성되어있고 64자리의 문자열을 반환해줍니다. 이러한 방식은 암호화된 문자열을 다시 원래의 문자열로 복호화할 수 없는 단방향 암호화 방식입니다. 입력값이 조금만 달리지더라도 변환되는 값이 완전히 달라지기 때문에 변환 값을 토대로 입력값을 유추하는 것은 거의 불가능합니다.
그러나 DB에 비밀번호를 평문에서 SHA-256 변환한 값으로 저장한다고 해도 레인보우 테이블의 등장으로 인해 해커가 암호화된 데이터가 무엇인지 알아내는 데는 많은 시간이 걸리지 않게 되었습니다.
레인보우 테이블?
원본-해시 쌍을 모아놓은 테이블로써, 123456, qwerty, iloveyou, qwe123, 111111과 같은 가장 많이 사용되는 비밀번호들은 물론, 지금 이 글을 읽으시는 이 시간에도 레인보우 테이블에는 수많은 해시값들이 쌓이고 있습니다.
하지만 문자열의 길이가 길면 길수록 레인보우 테이블에 원본-해시 쌍이 있을 확률이 현저히 떨어지고 더욱더 안전해지는데, 해커가 레인보우 테이블에 있는 값들과 대조하는 공격 방식에 대응하기 위해 평문과 salt(무작위의 랜덤 문자열을 소금처럼 뿌려준다는 의미..?)를 합친 문자열을 다시 SHA-256으로 암호화하는 방식입니다.
그렇기 때문에 SHA-256 암호화를 거친 평문+salt 문자열이 있는 DB가 외부에 노출된다 하더라도 해당 해시값은 레인보우 테이블에 없는 값이기 때문에 누구도 알아낼 방법이 없습니다.
📋 코드
package ex_packege;
import java.util.*;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.NoSuchAlgorithmException;
public class Main {
public static void main(String[] args) throws NoSuchAlgorithmException{
// 비밀번호 평문
String raw = "password1234";
String hex = "";
// "SHA1PRNG"은 알고리즘 이름
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
byte[] bytes = new byte[16];
random.nextBytes(bytes);
// SALT 생성
String salt = new String(Base64.getEncoder().encode(bytes));
String rawAndSalt = raw+salt;
System.out.println("raw : "+raw);
System.out.println("salt : "+salt);
MessageDigest md = MessageDigest.getInstance("SHA-256");
// 평문 암호화
md.update(raw.getBytes());
hex = String.format("%064x", new BigInteger(1, md.digest()));
System.out.println("raw의 해시값 : "+hex);
// 평문+salt 암호화
md.update(rawAndSalt.getBytes());
hex = String.format("%064x", new BigInteger(1, md.digest()));
System.out.println("raw+salt의 해시값 : "+hex);
}
}
https://www.convertstring.com/ko/Hash/SHA256
출력된 평문+salt의 해시값이 진짜인지 위의 사이트에서 직접 확인해보겠습니다.
이를 서비스의 로그인에 적용한다고 했을 때 랜덤으로 발생한 salt값과 비밀번호+salt를 암호화한 값을 DB 칼럼에 추가해줍니다. 그렇다면 사용자는 로그인할 때 아이디와 비밀번호 평문을 보내줄 것이고 서버에서는 해당 아이디를 가진 유저 레코드를 찾아 salt값을 가져옵니다. 그리고 파라미터로 넘겨받은 비밀번호 평문을 이용하여 암호화를 하여 해시 값을 얻은 후 유저 레코드에 암호화된 해시값과 일치한다면 인가, 일치하지 않는다면 미인가를 해주는 방식으로 처리하시면 됩니다.
'☕️JAVA' 카테고리의 다른 글
[JAVA] Deque(덱) 사용법 (0) | 2022.01.04 |
---|---|
[JAVA] Queue(큐) 사용법 (add vs offer / remove vs poll / element vs peek) (0) | 2021.12.07 |
[JAVA] 자바 형식화된 출력 - printf() 사용 예제 (0) | 2021.10.19 |
[JAVA] 자바 String to Int, Int to String 형변환 (0) | 2021.10.07 |
[JAVA] 명품 자바 에센셜 연습문제 3장 이론&실전 문제 풀이 (2) | 2021.01.11 |