Tip&Tech2014. 2. 2. 05:11

이번 설의 가장 큰 화두 중 하나는 "나도 개인정보 털렸어 ㅠㅠ" "언능 카드 재발급해" 이거네요. 

모두 개인정보 보호에 앞장서는 2014년이 됩시닷!!!! 


사용자 비밀번호는 단방향 암호화 함수로 암호화해서 저장하는 건 기본이죠? 


근데 

MySQL의 password() 함수는 한물 갔고 

crypt() 함수는 쉽게 뚫린다고 하고 

md5() 함수도 쉽게 뚫린다고 하고 

sha1() 함수도 곧 뚫릴 거라고 하고 

hash() 함수는 웬 듣도보도 못한 알고리듬이 그렇게 많은지? 


그래서 세계적인 보안 전문가들께서 추천하시는 비밀번호 암호화 방법들을 간단하게 정리해 보았습니다. 

웬만하면 보안 허술한 md5() 그만 쓰시고 아래의 방법들 중 하나 골라잡으세요. 



===================================================================================================== 



1. scrypt 



암호화 백업 서비스 tarsnap을 운영하는 

캐나다 프로그래머 콜린 퍼시벌(이름이 웬 ㅅㅂ이냐)이 개발한 암호화 알고리듬입니다. 

뚫기 어려운 걸로 말하자면 비교 대상이 없는 막강한 알고리듬이지만, 

너무 최신이라 PHP에서는 전혀 사용할 수 없으므로 패스. 



===================================================================================================== 



2. bcrypt 



해외에서 비밀번호 암호화에 대해 물어보면 즉시 돌아오는 모범답안입니다. 

예전부터 널리 사용되어 온 blowfish 양방향 암호화 알고리듬을 단방향으로 개조한 것으로, 

위에 언급한 scrypt를 제외하면 가장 막강한 후보입니다. 


PHP 5.5 이상에서는 아예 bcrypt 암호화 함수를 내장하고 있으므로 

아래와 같이 간단하게 사용 가능합니다. 



    암호화:  $hash = password_hash($password, PASSWORD_DEFAULT); 

                여기서 반환하는 $hash 값을 DB에 저장해 두었다가 아래에서 확인하는 데 씁니다. 


    확인:      if (password_verify($password, $hash)) { 

                    // 비밀번호가 맞음 

                } else { 

                    // 비밀번호가 틀림 

                } 



PHP 5.3.7 이상에서는 아래 링크의 파일을 인클루드한 후, 위와 똑같은 방법으로 쓰면 됩니다. 

위에서 사용한 내장 함수와 100% 호환됩니다. 

https://github.com/ircmaxell/password_compat/blob/master/lib/password.php 


그러나 대부분의 국내 웹호스팅에 설치되어 있는 PHP 5.2 버전에서는 bcrypt를 쓸 수가 없어요 ㅠㅠ 

예전부터 돌아다니던 phpass라는 라이브러리도 bcrypt를 지원한다고 하는데, 

이건 PHP 버전에 따라 그냥 md5() 함수를 사용해 버리기도 하더군요. 절대 비추입니다. 


그럼 어떻게 해야 할까요? 



===================================================================================================== 



3. PBKDF2 



RFC 2898에 규정되어 있으며, 세계 각국의 정부와 민간기업에서 오래 전부터 표준으로 쓰고 있는 알고리듬입니다. 

수많은 전문가들의 검증을 거쳤기 때문에 이거 썼다고 나무랄 사람은 아무도 없다는 것이 최대 장점이죠. 


게다가 bcrypt와 달리, 이건 PHP 5.1, 5.2 등에서도 대부분 사용이 가능합니다. 

흔히 쓰는 mcrypt 라이브러리가 설치되어 있고, 

hash_algos() 함수의 반환값 중 sha256이 포함되어 있는지만 확인하면 됩니다. 


표준 포맷을 PHP로 구현하는 소스는 아래의 주소에서 다운받아 인클루드하세요. 

https://defuse.ca/php-pbkdf2.htm 


최신 슈퍼컴퓨터로도 뚫기 어려운 강력한 보안을 원하시면 

PBKDF2_ITERATION 상수를 10000 정도로 바꿔주시는 것이 좋습니다. 

기본값은 1000 인데, 이건 아주 옛날에 쓰던 설정이라 요즘은 너무 낮다는 평가를 받아요. 

그러나 너무 높게 잡아놓으면 느려지므로 주의하세요. 



    암호화:  $hash = create_hash($password); 

                여기서 반환하는 $hash 값을 DB에 저장해 두었다가 아래에서 확인하는 데 씁니다. 


    확인:      if (validate_password($password, $hash)) { 

                    // 비밀번호가 맞음 

                } else { 

                    // 비밀번호가 틀림 

                } 



===================================================================================================== 



[부록] "저는 이미 md5() 쓰는데요? 이거 복호화도 안되는데 어떻게 bcrypt나 PBKDF2로 바꾸죠?" 


이런 질문 하실 분이 많을 것 같아서 부록을 준비했습니다. 

지금 쓰시는 알고리듬이 md5(), sha1(), 또는 비슷한 함수들의 조합이라면 

아래와 같이 하시면 됩니다. 


- 변환 작업 들어가기 전에 DB의 비밀번호 필드 자료형을 확인하고, 필요하다면 자료형을 바꿉니다. 

  예를 들어 md5() 함수는 항상 32바이트를 반환하므로 CHAR(32)로 해두셨을지도 몰라요. 

  그런데 bcrypt와 PBKDF2는 경우에 따라 60바이트 이상 반환하기도 합니다. 

  잘리지 않도록 필드 길이를 늘려주세요. VARCHAR(100) 정도 해두면 어떤 알고리듬이라도 넉넉합니다. 


- 기존의 회원 비밀번호는 암호화된 상태 그대로 bcrypt나 PBKDF2를 적용합니다. 

  미리 복호화할 필요 없어요. 


- 새로 가입하거나 비번 변경하는 회원은 기존의 알고리듬 한 번, 새 알고리듬 한 번, 이렇게 두 번 연달아 적용합니다. 

  예를 들어 XE처럼 md5(sha1(md5($password))) 이런 방식이었다면 

  password_hash(md5(sha1(md5($password)))) 이렇게 함수를 하나 더하는 거죠. 

  그러면 기존의 회원 비밀번호와 동일한 형식으로 통일되겠죠? 


- 비밀번호 체크할 때도 똑같이 하면 됩니다. 알고 보니 쉽죠? 

  예를 들면 if (password_verify(md5(sha1(md5($password))), $hash)) 


- 함수를 여러 개 쓰면 느려지지 않냐고요? 

  md5() 수천 번 돌려봤자 bcrypt나 PBKDF2 한 번 돌리는 것보다 시간 적게 걸립니다. 

  bcrypt나 PBKDF2는 딱 한 번만 돌리세요. 나머지는 아무리 많이 돌려봤자 차이를 느낄 수 없습니다. 


- 주의!!! 기존의 알고리듬이 "솔트"를 사용하고 있다면 위와 같이 쉽게 변환할 수 없습니다. 예: crypt() 함수 

  이 경우는 좀더 복잡한 과정을 거쳐야 하고, 잘못하면 다 틀려지니 주의하세요. 

  만약 솔트가 뭔지 모르신다면 해당 없습니다.


출처 : http://www.phpschool.com/link/tipntech/78316


Posted by 네로