반응형

 

🧐 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값을 가져옵니다. 그리고 파라미터로 넘겨받은 비밀번호 평문을 이용하여 암호화를 하여 해시 값을 얻은 후 유저 레코드에 암호화된 해시값과 일치한다면 인가, 일치하지 않는다면 미인가를 해주는 방식으로 처리하시면 됩니다.

 

 

 

 

 

반응형

+ Recent posts