http://www.mimul.com/pebble/default/2013/02/18/1361189648941.html
최근 들어서 개인 정보 유출 등으로 인해 개인 정보 암호화 방법에 대해서 많이들 고민할 것입니다.
그 중에서 가장 중요하게 생각하는 것 중에 하나가 사용자의 패스워드인데, 과거에는 대부분 해시 MD5, SHA1 또는 SHA-256을 사용하고 있고, 좀 더 안다는 고급 개발자들이 있는 기업들만이 패스워드에 salt를 넣어 사용하고 있는 것으로 파악됩니다.(제가 잘못 알고 있을수도 있습니다.) 물론 최근들어 KISA의 제재로 salt + SHA1로 가는 추세이긴 합니다.
그러나 SHA1 + salt가 안전하다고 생각하는 분들은 아마 없을 듯 합니다. 그저 정부의 제재 수단을 회피하고자 적용하는 기업들이 많을 겁니다.
SHA1 + salt로 패스워드 보안 이슈 회피가 가능한가?
MD5, SHA1 또는 SHA-256 알고리즘은 보안이 우수하지 않다는 것은 다음 사이트에서 테스트해 보면 알 수 있습니다.
"http://google.com"을 MD5 인코딩한 값(c7b920f57e553df2bb68272f61570210)을 md5.rednoize.com 사이트에 넣고 검색 버튼을 클릭하면 바로 복호화되어 나옵니다.
이 md5.rednoize.com은 원본 데이터와 해시값의 데이터베이스를 참조해, 등록된 것은 즉시 해시값에서 데이터로 변환되어 출력하게 되는 구조입니다. 딕셔너리가 많이 확보되면 쉽게 패스워드를 풀 수 있게 된다는 소리도 됩니다.
이처럼 Rainbow Table("해시값이 이것이면, 암호는 이것"라는 테이블)을 사용해 일방향 암호화 기술을 무력화하게 됩니다. 이것만으로 보아도 일방향 암호화 알고리즘으로 MD5, SHA1 또는 SHA-256은 이제 한물간 일방향 암호화 알고리즘이라는 것을 쉽게 알 수 있죠.
그래서 보완책으로 나온 것이 SHA1 + salt입니다. salt를 붙이는 것으로, Rainbow Table 사용 접근 방식을 실질적으로 사용할 수 없게 하는 것으로 생각해 왔습니다.
SHA1 + salt의 처리방식은 아래와 같습니다.
$salt = "this is a salt"; $password = 'this is an password'; $hash = sha1($salt.$password);
자! 이 방법 또한 여기를 보듯이 GPU가 장착된 디바이스로 병렬처리하면 초당 수억건의 처리가 가능해 무력화 기술에 의해 무너질 수 있습니다. 이렇게 되면 딕셔너리 공격과 무력의 기술을 결합하여 많은 계정을 가진 대형 사이트에서도 상당한 양의 암호를 해독하는데, 그리 오랜 시간이 걸리지 않을 것입니다.
현재까지의 좀 더 강화된 방법으로는 뭐가 있을까요?
- 각 사용자에게 고유 salt 값과 반복 횟수를 마련하는 것이고.
- 좀 더 강력한 PBKDF2(http://en.wikipedia.org/wiki/PBKDF2), Bcrypt(http://www.openwall.com/crypt/), HMAC(http://en.wikipedia.org/wiki/HMAC)를 사용하는 것.
- 불편하더라도 사용자에게 강한 강도의 패스워드를 받도록 유도하는 것.
정도가 될 것으로 보입니다.
PBKDF2 사용 샘플(Java)
public class PBKDF2 { //임의 salt를 생성 private static byte[] createSalt() throws NoSuchAlgorithmException { SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); byte[] salt = new byte[32]; random.nextBytes(salt); return salt; } private static byte[] pbkdf2(char[] password, byte[] salt) throws InvalidKeySpecException, NoSuchAlgorithmException { SecretKeyFactory sf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); // 반복 횟수 : 10000 번 결과 길이 : 256bit KeySpec ks = new PBEKeySpec(password, salt, 10000, 256); SecretKey sk = sf.generateSecret(ks); return sk.getEncoded(); } private static void logging(String format, Object ... args) { System.out.printf(format + "%n", args); } public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException { String p1 = args[0]; String p2 = args[1]; logging("password 1= %s", p1); logging("password 2= %s", p2); byte[] salt = createSalt(); logging("salt: %s", Arrays.toString(salt)); byte[] d1 = pbkdf2(p1.toCharArray(), salt); byte[] d2 = pbkdf2(p2.toCharArray(), salt); logging("derived 1= %s", Arrays.toString(d1)); logging("derived 2= %s", Arrays.toString(d2)); } }
위의 10000이라는 숫자가 반복횟수이므로 이를 증가시켜 안전성을 높일 수 있습니다. 이 수를 사용자별로 데이터베이스에 저장하여 두면 중간에 반복 횟수를 높이고 안전성을 향상시킬 수도 있습니다.
[참조사이트]
'Computer' 카테고리의 다른 글
TreeSize Free - Quickly Scan Directory Sizes and Find Space Hogs (0) | 2014.05.19 |
---|---|
emacs cheat sheet (0) | 2014.05.03 |
Excel/엑셀 VBA] 반각 문자/ 전각 문자 변환; Half-Width Full-Width Char Convert (0) | 2014.03.05 |
HTML 4 Transitional Document Type Definition (0) | 2014.02.25 |
한글 자동서식 해제 (0) | 2014.01.27 |