Python 에서 SHA256, SHA512, MD5 해시를 통한 비밀번호 암호화 방법 - Whitmem
Python 에서 SHA256, SHA512, MD5 해시를 통한 비밀번호 암호화 방법
Python Programming
2025-04-24 20:27 게시 beba09ce60566d0a7ab8

0
0
42
이 페이지는 외부 공간에 무단 복제할 수 없으며 오직 있는 그대로 게시되며 부정확한 내용을 포함할 수 있습니다. 법률이 허용하는 한 가이드 라인에 맞춰 게시 내용을 인용하거나 출처로 표기할 수 있습니다.
This page is not to be distributed to external services; it is provided as is and may contain inaccuracies.
기본적으로 사용자 비밀번호를 암호화하기 위해서는 해시 단방향 암호화를 사용한다.
단방향 암호화는 일반 양방향 암호화와는 전혀 차원이 다른데, 비밀번호를 암호화하는 데 사용되는 해시 알고리즘은 사실상 비밀번호를 숨기는 암호화만을 위한 알고리즘이 아니라고 보기도 한다. (보통 무결성을 검증하는데 사용된다.)
즉 해시는 암호학 알고리즘보다 어떤 출력을 내 뱉는 함수라고 이해할 수 있는데, 매우 유용하고 알고리즘적으로 비밀번호 처리에도 안전해서 비밀번호를 암호화하는데 자주 사용되고 있다.
비밀번호의 암호화 방법
어떻게 사용자 비밀번호를 안전하게 데이터 베이스에 저장할 수 있을까? 기본적으로 비밀번호를 암호화하여 저장하는 이유는 서버의 사용자 계정 데이터베이스가 유출되더라도 피해를 최소화하기 위함이다.
중요한 것은 사용자 비밀번호는 보통 복호할 수 없는 형태로 암호화해야 한다. 이는 즉 한번 암호화하면 절대 복호되어서는 안된다는 것이다. 만약 우리가 흔히 알고 있는 암호키 기반으로 비밀번호를 암호화한다면, 이 암호키가 유출되면 비밀번호도 모두 유출된다는 문제가 존재한다.
그렇기 때문에 보통 사용자 비밀번호는 해시 방법으로 암호화를 하는데, 해시는 어떤 x 입력에 대해 고정된 길이의 y를 내뱉는 함수이다. 즉 같은 x에 대해서는 항상 같은 y를 내뱉기 때문에 비밀번호가 동일한지 확인하기 위해서는 해시된 비밀번호를 저장하고, 사용자가 입력한 비밀번호를 해시해서 서로 비교하면 되는 것이다.
기본적으로 과거 자주 사용됐던 해시 함수는 MD5가 있다
import hashlib password="비밀번호" md5_instance = hashlib.md5(password.encode()) md5_instance.hexdigest()
파이썬에서는 hashlib 이라는 내장 라이브러리를 사용해서 손쉽게 해시 함수를 사용할 수 있다. 먼저 hashlib 내 md5 클래스의 인자에 해시하고자 하는 입력 값을 넣어주면 된다.
단, 입력 값은 반드시 바이트 배열로 넘겨야하기 때문에, String 형태인 비밀번호를 encode() 하여 바이너리 데이터 형식으로 변환하고, md5에 넘겨주면 된다.
그러면 md5_instance 인스턴스가 생기는데, 여기서 hexdigest()를 하여 결과물을 hex string 으로 뿌려주면 흔히 데이터베이스에 저장할 수 있는 암호화된 비밀번호가 생성되는 것이다.
즉 위 상황에서 MD5 해시 알고리즘에 대해 '비밀번호'라는 String 의 입력 값은 항상 cd504c7c56a3821206c416fb5460f384 라는 출력 값이 나오게 된다. 데이터 베이스에는 cd504c7c56a3821206c416fb5460f384 라는 값을 저장해두고, 사용자가 로그인하는 즉시 즉시 입력 값을 해시화 하여 해시된 문자열과 비교하면 되는 것이다. 그러면 비밀번호의 원문을 알 필요 없이 해시된 비밀번호만 가지고 제대로된 비밀번호가 입력됐는지 확인할 수 있다.
_dict = {"USER1":"cd504c7c56a3821206c416fb5460f384"} def encrypt(password): import hashlib md5_instance = hashlib.md5(password.encode()) return md5_instance.hexdigest() if(encrypt("새 비밀번호")==_dict["USER1"]): print("비밀번호가 맞습니다.") else: print("틀린 비밀번호입니다.")
틀린 비밀번호입니다. 일단 Hash 알고리즘으로 비밀번호를 저장하고 관리하면 적어도 복호화는 절대 불가능하다. 해시 함수는 아무리 긴 입력에 대해서도 결과적으로 동일한 길이의 문장을 내뱉기 때문에, 수학적으로 해당 y를 가르키는 x는 무수히 많다.
즉 y에서 x로 돌아가려고 한들 사실상 찾기가 쉽지 않다는 것이다.
하지만 반대로 생각해보면, 의구심이 하나 들텐데 바로 중복되는 y에 대한 문제이다.
해시 함수는 아무리 긴 입력에 대해서도 고정 길이의 y를 내뱉기 때문에 언젠가는 동일한 y 가 나올 수 있다. 하지만 이론적으로 그런 것이지, 사실상 찾는 것이 불가능하다. (가능하다고 해도 현재 컴퓨팅 성능으로는 무수히 긴 시간이 필요로 하다. 이러한 원리가 기존 블록 체인의 Pow 채굴 시스템의 기반이 되기도 한다.)
동일한 y가 발견되는 경우 그 해시 함수는 사실상 '깨진 해시 함수' 또는 '충돌이 발생한 해시 함수'라고 표현하며 더 이상 사용해서는 안되는 해시 함수로 평가되기도 한다. 대표적인 사례가 MD5 이다.
https://en.m.wikipedia.org/wiki/MD5
자세한 건 위키 백과의 MD5 문서를 참고하길 바란다.
그렇기 때문에, 현재 시점에서는 MD5 는 파일의 무결성을 검증하는 용도 말고는 비밀번호 보호 용도로는 거의 사용되지 않는다. 비밀번호 보호를 위해서는 적어도 SHA256, SHA512와 같은 해시 알고리즘을 사용하는 것이 안전하다.
import hashlib password="비밀번호" md5_instance = hashlib.sha256(password.encode()) md5_instance.hexdigest()
SHA256 또는 SHA512 사용 방법은 어렵지 않다. hashlib 안에서 모두 제공되기 때문에 원하는 알고리즘의 클래스로 변경하기만 하면 된다.
import hashlib password="비밀번호" md5_instance = hashlib.sha512(password.encode()) md5_instance.hexdigest()
SHA 의 숫자는 각 비트 수를 의미한다. 해시 처리의 암호학적인 내용은 해당 알고리즘의 문서를 참고하기를 권한다. 여기서는 단순히 사용하는 것이기 때문에 숫자가 클수록(비트가 클수록) 더 안전하다고 보면된다. 하지만 사실상 256, 512 둘다 자주 사용된다.
한편 위 암호 해시는 실무상으로 사용되기에는 다소 무리가 있다. 그 이유는 Rainbow 테이블에 의해 공격 당할 우려가 존재하기 때문이다. 해시 함수는 기본적으로 x 입력에 대해서 동일한 y 입력을 내뱉기 때문에, 이미 다른 고성능 자원을 활용하여 사람들이 사용할만한 x 입력에 대해서 y를 미리 예측해둔 데이터 베이스 테이블이 존재한다. 즉 이 공격용 데이터 자료라고 보면된다. 여기에는 적어도 수백만 행, 수천만 행의 난수 또는 랜덤 글자에 대해 해시된 결과 정보가 담겨 있는데, 이 테이블을 사용하면 적어도 빠르게 비밀번호가 복호될 우려가 존재한다.
또한, 다른 데이터 베이스가 유출되거나 한 서버 안에서 서로 다른 계정에 대해서 동일한 비밀번호를 사용하고 있으면 해시 값이 똑같아 한 번에 비밀번호를 추정할 수 있게 되는 보안 우려가 발생한다는 문제가 존재한다. 즉 수십만 사용자의 계정 데이터 베이스가 유출됐을 때, 한 사용자의 비밀번호만 알아낸 뒤, 해당 사용자의 비밀번호와 동일한 계정을 바로 찾을 수 있게 되는 것이다.
이러한 문제를 최소화하기 위해서 해시 암호에 SALT 기법을 사용해 안전하게 보호하는데, 소금을 친다고 표현하기도 한다.
import hashlib import random password="비밀번호" random_code = int(random.random() * 100000000) password+=str(random_code) md5_instance = hashlib.sha256(password.encode()) md5_instance.hexdigest()
위 코드를 보면 사용자가 입력한 비밀번호 password 에 임의의 난수를 끝에 concat 하고 이 값을 SHA256 해시에 넣고 있다. 이러면 이 명령을 수행할 때 마다 난수가 비밀번호 뒤에 넣어져 들어가지기 때문에 항상 다른 해시가 도출된다.
"비밀번호15235"
"비밀번호15234"
"비밀번호61030"
그리고, 이 랜덤 코드 정보를 완성된 해쉬 뒤에 붙여 같이 데이터 베이스에 저장한다. 이 때 해시 영역과 랜덤 코드 영역을 구별할 수 있도록 split 문자열을 &로 하여금 구분자를 지정하여 하나의 String 으로 나타낸다.
import hashlib import random password="비밀번호" random_code = int(random.random() * 100000000) password+=str(random_code) md5_instance = hashlib.sha256(password.encode()) md5_instance.hexdigest() + "&" + str(random_code)
즉 비밀번호를 해시할 때에는 실제 비밀번호 뒤에 해시 값을 붙여 해싱하고, 그 결과 끝에 & 를 사용하여 랜덤 코드를 같이 기록한다.
저장된 비밀번호 해시와 비교하기 위해, 저장된 해시 값에서 먼저 랜덤 코드를 추출하고, 랜덤 코드를 사용자가 입력한 비밀번호 끝에 붙여 해싱함으로써 데이터 베이스에 저장된 비밀번호 해시와 동일한지 확인할 수 있다.
_dict = {"USER1":'224db42cbe9f3cd7efa641b902c9ff57f6b2b99915c879defac7b83f4ded9bfe&4918052'} def verifyPassword(password, savedHash): randomCode = savedHash.split("&")[1] password += str(randomCode) instance = hashlib.sha256(password.encode()) return instance.hexdigest() == savedHash.split("&")[0] if(verifyPassword("비밀번호",_dict["USER1"])): print("비밀번호가 맞습니다.") else: print("비밀번호가 틀립니다.")
즉 비밀번호를 해싱할 때는 랜덤 코드를 난수로 지정하여 해시 결과를 생성하고, 비밀번호를 검증할 때는 이미 데이터 베이스에 저장된 해시 결과를 가져와 랜덤 코드를 분할 해 해당 랜덤 코드로 사용자가 입력한 비밀번호 뒤에 붙여 해싱한 다음 해시 영역과 비교하여 동일한지 확인하면 되는 것이다.
즉 해시 결과를 생성할 때에는 항상 랜덤 해시 결과가 출력되다가, 검증할 때는 해당 랜덤 코드 정보를 받아 사용자가 입력한 비밀번호를 해싱하여 비교하면 된다.
이러한 방법을 통하면 같은 데이터 베이스 안 또는 이미 공격된 테이블 목록이 존재하더라도 끝에 난수가 붙어있기 때문에 완전 다른 해시 결과가 출력되어 원본 비밀번호의 유추가 불가능해진다.
비밀번호 관리시 유의 사항
기본적으로 사용자 비밀번호는 직접 암호 패키지를 구현해서 사용하기 보다 이미 공개돼 검증된 라이브러리를 사용하는 것이 낫다. 잘못된 암호 알고리즘의 사용법은 오히려 치명적인 문제를 일으킬 수 있는데다가 잠재적 문제를 통해 대형 사고로 이어질 수 있다.
따라서 보통 사용자 비밀번호와 같은 민감 정보의 경우, SHA512 를 단독으로 사용하기 보다 비밀번호 해싱을 위한 라이브러리인 BCrypt 등을 사용하는 것을 권장한다. 특히 위와 같은 암호화 알고리즘은 속도가 무조건 빠르다고 해서 좋은 것도 아니다. 속도가 빠르다는 것은 컴퓨팅 성능이 뛰어나다는 것이고, 역으로 말하면 브루트 공격에 취약하다는 말이 될 수도 있다. Bcrypt 는 다양한 암호 강도 조절을 통해 해독 성능을 조절할 수 있기에 무작위 공격에도 비교적 안전하다는 장점이 있다.
댓글 0개
댓글은 일회용 패스워드가 발급되며 사이트 이용 약관에 동의로 간주됩니다.
확인
Whitmemit 개인 일지 블로그는 개인이 운영하는 정보 공유 공간으로 사용자의 민감한 개인 정보를 직접 요구하거나 요청하지 않습니다. 기본적인 사이트 방문시 처리되는 처리 정보에 대해서는 '사이트 처리 방침'을 참고하십시오. 추가적인 기능의 제공을 위하여 쿠키 정보를 사용하고 있습니다. Whitmemit 에서 처리하는 정보는 식별 용도로 사용되며 기타 글꼴 및 폰트 라이브러리에서 쿠키 정보를 사용할 수 있습니다.
이 자료는 모두 필수 자료로 간주되며, 사이트 이용을 하거나, 탐색하는 경우 동의로 간주합니다.