본문 바로가기
개발지식

사용자 비밀번호 암호화 - Hash & Salt

by devLog by Ronnie's 2021. 9. 23.

들어가며


웹 프로젝트를 하다보면 사용자의 비밀번호를 다루게 되는 일이 생긴다.

이 프로젝트가 실제로 서비스가 되고 있는 프로젝트라면 사용자의 비밀번호를 다루는 일은 보안상에 있어서 아주 중요한 부분일 것이다. 

 

만약 이러한 비밀번호를 디비에 그냥 평문으로 저장하게 된다면 해커에 의해서 디비가 털리는 순간 큰 문제가 생길 것이다. 그렇기 때문에 사용자 비밀번호를 저장하는 것은 중요한 일이다.

 

 들어가기 앞서 해싱과 암호화에 차이를 먼저 짚고 넘어간다.

 

 

 

사용자 비밀번호 암호화 - Hash & Salt


해싱과 암화화는 일상 생활에서 어느정도 의미가 통용되지만 암호학적으로 볼때는 차이가 있다. 그 차이는 바로 방향성에 차이인데 암호화는 양방향에 방향성을 가지고 있기에 암호화 <-> 복호화 가 가능하다. 해싱은 단방향이기 때문에 복호화가 불가능하다.

 

이걸 알았으면 이제 왜 비밀번호를 해싱을 이용해서 해야되는지 알 것이다. 

 

 

 

Hash


단방향 해시 함수는 특정 알고리즘을 이용하여 원본 데이터를 매핑시켜서 암호화된 데이터로 반환시켜준다. 이러한 변환을 해시라고 하고 해시에 의해서 변환된 데이터는 다이제스트라고 부른다.

 

이때 이용되는 해시 함수의 알고리즘 종류들은 여러가지가 있다. 그 중 대표적인 알고리즘은 다음과 같다.

 

1. SHA

2. MD

3. HAS

4. WHIRLPOOL

 

이 중에서 가장 대표적인 SHA-256을 통해서 '1234'를 암호화해보면 다음과 같이 나온다.

https://emn178.github.io/online-tools/sha256.html

이 사이트를 통해서 여러가지 해시 알고리즘을 통해 암호화 테스트를 해볼 수 있다.

 

'1234'에 숫자를 하나만 추가하더라도 완전히 다른 결과가 나오는 것을 확인할 수 있다. 그만큼 디비가 털려서 해시값을 알게 되더라도 원본에 비밀번호 값을 유추하기란 쉬운 일이 아니다.

 

Hash 한계


위에서 말했듯이 해시를 사용하게 되면 비밀번호를 유추하기란 쉬운일이 아니다. 하지만 비밀번호를 유추하는 것이 불가능한 것은 아니다. 즉 한계점이 있다는 말인데 한계점은 다음과 같다.

 

1. 동일 메시지는 동일한 다이제스트 값을 가진다.

 

이 말은 즉 비밀번호 원본을 모르더라도 해시된 다이제스트 값을 알면 찾을수도 있다는 말인데 그것을 도와주는 것이 바로 레인보우 테이블이다. 이 테이블은 그동안 해커들이 여러 값들을 대입해보면서 얻었던 다이제스트들을 모아놓은 리스트이다. 다음 사이트에 들어가보면 테스트가 가능하다.

https://crackstation.net/

 

CrackStation - Online Password Hash Cracking - MD5, SHA1, Linux, Rainbow Tables, etc.

Free Password Hash Cracker Enter up to 20 non-salted hashes, one per line: Supports: LM, NTLM, md2, md4, md5, md5(md5_hex), md5-half, sha1, sha224, sha256, sha384, sha512, ripeMD160, whirlpool, MySQL 4.1+ (sha1(sha1_bin)), QubesV3.1BackupDefaults How Crack

crackstation.net

 

위에서 테스트했던 '12341' 이라는 비밀번호의 해시값을 해당 사이트에 입력해보면 결과로 12341이 나오는 것을 확인할 수 있다. '12341'이라는 숫자가 워낙 단순하기에 해당 테이블에 등록되어 있는 것이다. 이렇게 단순한 비밀번호는 이미 해커들이 대입해보았을 확률이 높기에 해당 값의 다이제스트 값이 레인보우 테이블에 있을 가능성도 높을 것도 유추해볼 수 있다.

2. 무차별 대입 공격

 

해시 함수의 경우는 원래 암호화에 이용하기 위해서가 아닌 빠른 데이터 검색을 위한 목적을 설계되었다. 그렇다보니 다이제스트 값을 금방 얻어낼 수 있다. 바로 이러한 점이 문제가 된다. 다이제스트를 빠르게 얻을 수 있다는 점은 해커 입장에서도 마찬가지이므로 무작위의 데이터들을 계속 대입해보면서 얻은 다이제스트와 해킹할 대상의 다이제스트를 계속 비교해보는 것이다. 하지만 경우의 수는 워낙에 많기 때문에 아주 복잡하게 생성한 암호는 찾기 어렵겠지만 위에서도 봤듯이 간단한 비밀번호라면 그리 시간이 오래 걸리지 않을 것이다. 

 

 

 

Hash 보완


이제 한계점을 알았으니 보완 방법에 대해 알아보자.

가장 유명한 방법으로는 키-스트레칭과 솔트가 있다.

 

1. 키-스트레칭

 

이 방법은 처음 돌려서 나온 다이제스트를 다시 한번 더 돌리는 것이다. 이렇게 되면 정확한 횟수를 알더라도 그만큼 시간이 소요가 되기 때문에 해커입장에서는 곤란해진다. 어느정도 보완이 가능은 하지만 뭔가 부족한 느낌이다. 이를 방지하기 위해 도입된 방법이 두번째 방법인 솔트이다.

 

2. 솔트 (SALT)

 

솔트란 해시함수를 돌리기 전에 원문에 임의의 문자열을 덧붙이는 것을 말한다. 이렇게 되면 다이제스트를 알아내더라도 임의의 문자열이 덧붙여졌기에 유추하기는 더욱 힘들어진다. 공통으로 사용하는 SALT가 아니라면 사용자들의 비밀번호가 겹치는 경우 그 중 한사람의 다이제스트가 유출이 되더라도 다른 SALT값을 사용하므로 같은 비밀번호를 사용하고 있는 사용자의 대한 보안도 지킬수 있다. 여기에 더불어서 솔트의 가장 큰 목적은 해당 솔트를 알아내더라도 해당 솔트가 추가 된 레인보우 테이블을 새로 생성하여 만들기에는 엄청나게 큰 데이터를 필요로 하기 때문에 이러한 점도 해킹 시도를 방지해주는 역할을 한다. 

 

 

마치며


처음에는 비밀번호를 평문으로 저장하는 것에 대해서 그렇게 크게 문제라고 생각하지 않았는데 이 글을 정리하면서 얼마나 잘못된 생각인지 깨닫게 되었다. 개발자 입장에서도 보안 관련된 부분은 정말 중요하지 않을 수 없는 것처럼 이러한 부분들의 관하여 계속 알아나가야 겠다.

 

 

 

 

 

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

댓글