[JAVA] 비밀번호 암호화 하기 SHA-256 알고리즘 + Salt 적용 예제 - 레인보우 테이블 :: 매운코딩
728x90
300x250

SHA 256 알고리즘?

해시값을 이용한 암호화 방식 중 하나로 단방향 알고리즘이다.

단방향이란 암호화는 가능하나 복호화가 불가능한 것을 의미한다.

일반적인 "ABC"라는 값을 SHA-256알고리즘을 적용하면 "4d35adf24fe634er..."과 같은 64자리의 문자열로 반환한다.

"ABC"와 "ABCD"의 암호화된 해시값은 천지 차이이기 때문에 단순 암호화된 해시값으로는

원래의 문자열을 절대 유추할 수가 없다.

 

대체적으로 보안상의 이슈로 DB상에 비밀번호를 직접적으로 넣다기 보다는 이렇게 SHA256을 적용한 문자열을 넣는다. 로그인 할때에는 사용자가 입력한 비밀번호를 다시 SHA256를 적용하여 DB값과 맞는지 비교한 후 Access한다.

 

그런데.. 레인보우 테이블이 생기고 이를 통해 해커가 암호화된 데이터가 무엇인지 알아내게 되었다.

 

레인보우 테이블?

원본 문자열과 - 암호화된 해시값을 Key-Value 한 쌍의 형태로 저장해놓은 테이블이다.

레인보우 테이블에 계속해서 수많은 데이터들이 쌓이면서.. 암호화된 해시값을 역으로 추적하여 원본 문자열을 알아내게 된것이다.

악..그럼 모두의 비밀번호가 털리는 것은 시간문제.....이를 막고자 Salt라는 방식이 등장한다.

 

Salt?

소금이다. 소금이 갑자기 왜나와?

레인보우 테이블은 원본 문자열이 길고 복잡 할수록 테이블에 존재할 가능성이 낮아진다.

이런 약점(?)을 이용해서 생긴 방식이다.

원본 문자열에 무작위 랜덤 문자열(Salt)를 합치고 그것을 SHA 256 알고리즘에 적용 시키는 것이다.

원본에 소금(무작위 문자열)을 친다고 보면된다.

그럼 문자열이 더 길고 복잡해지니까 레인보우 테이블에 존재하지 않을거고..그럼 난 안전하다..?!

 

로그인 할 때는 ID로 Salt값을 조회하여 입력한 비밀번호와 Salt 값을 다시 암호화 하여 비밀번호를 체킹한다.

(USER 테이블에 SALT라는 컬럼이 생성되어야겠죠..)

 

 

SHA256 + Salt 적용 코드 예제

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public class Encrypt {

	public static void main(String[] args) {
		Encrypt en = new Encrypt();
		
		String pwd = "cceeun.tistory";
		System.out.println("pwd : "+ pwd);
		
		//Salt 생성
		String salt = en.getSalt();
		System.out.println("salt : "+salt);
		
		//최종 pwd 생성
		String res = en.getEncrypt(pwd, salt);
	}

	public String getSalt() {
		
		//1. Random, byte 객체 생성
		SecureRandom  r = new SecureRandom ();
		byte[] salt = new byte[20];
		
		//2. 난수 생성
		r.nextBytes(salt);
		
		//3. byte To String (10진수의 문자열로 변경)
		StringBuffer sb = new StringBuffer();
		for(byte b : salt) {
			sb.append(String.format("%02x", b));
		};
		
		return sb.toString();
	}
	
	public String getEncrypt(String pwd, String salt) {
		
		String result = "";
		try {
			//1. SHA256 알고리즘 객체 생성
			MessageDigest md = MessageDigest.getInstance("SHA-256");
			
			//2. pwd와 salt 합친 문자열에 SHA 256 적용
			System.out.println("pwd + salt 적용 전 : " + pwd+salt);
			md.update((pwd+salt).getBytes());
			byte[] pwdsalt = md.digest();
			
			//3. byte To String (10진수의 문자열로 변경)
			StringBuffer sb = new StringBuffer();
			for (byte b : pwdsalt) {
				sb.append(String.format("%02x", b));
			}
			
			result=sb.toString();
			System.out.println("pwd + salt 적용 후 : " + result);
			
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}

		return result;
	}
}

 

 

실제로 저 코드를 돌려보니 이렇게 나왔다. 

pwd : cceeun.tistory
salt : b4b9d0daae6bf78df93897aad738a6baf83033de
pwd + salt 적용 전 : cceeun.tistoryb4b9d0daae6bf78df93897aad738a6baf83033de
pwd + salt 적용 후 : 57611f257d3f5a1ee957688391d6bb8d85372fc91539fbdf2434a47665b68556

https://www.convertstring.com/ko/Hash/SHA256

위의 사이트에서 SHA256이 잘 적용된게 맞는지 확인할 수 있다.

적용해보니 동일하게 나왔다!

 

 

 

 

참고자료-

https://cocoon1787.tistory.com/832

https://ohtanja.tistory.com/3

728x90

+ Recent posts