패스워드를 안전하게 저장하는 방법엔 어느정도 정답이 나와있다.
중 하나를 사용해서 패스워드를 암호화하면 된다.
최근 공부했던 Django와 같은 프레임 워크에서는 기본적으로 강력한 패스워드 저장 방식을 채택하고 있어 안전하게 저장할 수 있다고 한다.
Django에서는 PBKDF2를 사용한다.
brute force는 말그대로 조합가능한 모든 패스워드를 다 대입해보는 것이다.
당연히 대입해서 똑같은 해시값이 나오면 뚫은 것이다.
기본적으로 모든 해시는 brute force로 뚫을 수 있다.
그렇기 때문에 당연히 대입해서 정답을 찾아내는 시간을 아주 오래걸리게 만들어서 뚫기 어렵게 만드는 것이 기본이다.
MD5는 이 brute-force attack으로 빠른 시간안에 뚫을 수 있다.
md5는 25개의 GPU로 초당 1800억개 대입이 가능하다고 한다.
단순히 영문 대소문자, 숫자만 조합한 8자리 고정 패스워드라면 62^8개의 조합이다. 이 정도는 62^8개/1800억개로 1213초, 대충 20분정도면 정답을 찾아낼 수 있다.
GPU를 이용한 brute force 공격은 굉장히 빠르다.
해시 알고리즘을 엄청 복잡하게 만들어 Brute-force 공격에서 안전해질지도 모른다.
다만 더 효율적인 정답도출 방식이 있다.
미리 가능한 패스워드 조합을 다 계산한 테이블을 가지고 비교만 수행하는 것이다.
이것을 dictionary attack이라 하고, 이 dictionary를 해시값 검색에 최적화 시킨 것이 rainbow table이라고 한다.
md5는 인터넷에 이미 수백억개의 해시값에 대한 rainbow table이 있다.
공개된 md5 rainbow table만 사용해도 대부분의 웹사이트에서 90% 정도의 사용자 패스워드가 크랙된다고 한다.
다만, rainbow table을 만드는데 시간이 많이 들기도 하고 알고리즘의 복잡도가 상관이 없는 것은 안디ㅏ.
알고리즘 수행시간이 길면 충분한 규모의 rainbow table을 확보하기도 어렵다.
그래도 쉬운 패스워드는 뚫리므로 보안성을 크게 높일 수 있다고 말하기는 어렵다.
해시에 대해 다양한 크랙 수단이 있지만, 가장 효율적인 수단은 rainbow table이다.
다만, 단순히 동일한 salt 값을 추가하는 것만으로 미리 게산해놓은 rainbow table은 꽤 무력해진다.
당연히 고정값 salt만 있으면 rainbow table에서 salt까지 포함하는 테이블을 만들 수도 있다.
예를 들어 salt길이가 1글자라면 rainbow table을 만들 때 패스워드 허용 문자 개수를 곱한만큼 만들면 된다.
사이즈는 커지지만 상대적으로 훨씬 더 커지는 rainbow table의 사이즈를 생각하면 괜찮다.
salt는 최소 128bit 정도는 되어야 안전하다고 한다.
salt로 rainbow table을 막았다면 brute-force가 아직 남아있다.
brute-force는 원천적으로 봉쇄할 방법은 없고 암호화 알고리즘을 느리게 만들어 공격효율을 낮게 만드는 방법 뿐이다.
이것에 대해 엄청나게 복잡한 알고리즘을 써서 느리게 만들기 보다는,
알고리즘 수행 시간을 조정가능하게 만드는 방법이 더 좋다.
컴퓨팅 파워는 시간이 갈수록 더 좋아지기만 한다.
알고리즘 수행시간을 조정하는 가장 쉬운 방법은 해싱을 반복하는 것이다.
PBKDF2의 경우 반복횟수를 조정할 수 있는데 권장하는 최소 반복횟수는 1000번이다.
가장 많이 사용되는 key derivation function은 PBKDF2(Password-Based Key Derivation Function)이다.
해시 함수의 컨테이너인 PBKDF2는 솔트를 적용한 후 해시 함수의 반복횟수를 임의로 선택할 수 있따.
PBKDF2는 매우 가볍고 구현하기 쉽다. SHA와 같이 검증된 해시 함수만을 사용한다.
PBKDF2는 기본 파라미터로 5가지의 파라미터를 가지고 있다.
DIGEST = PBKDF2(PRF, Password, Salt, c, DLen)
PBKDF2는 NIST에 의해 승은된 알고리즘이며, 미국 정부 시스템에서도 사용자 패스워드의 암호화된 다이제스트를 생성할 때 사용한다.
Bcrypt는 1999년에 publish된 password-hashing function이다.
Blowfish 암호를 기반으로 설계된 암호화 함수이며, 현재까지 사용중인 가장 강력한 해시 메커니즘 중 하나이다.
반복횟수를 늘려 연산속도를 늦출 수 있으므로 연산 능력이 증가하더라도 brute-force 공격에 대비할 수 있다.
bcrypt에서 work facor 인자는 하나의 해시 다이제스트를 생성하는데 얼마만큼의 처리 과정을 수행할지 결정한다.
work factor를 조정하는 것만으로 간단하게 시스템의 보안성을 높일 수 있다.
PBKDF2나 scrypt와는 다르게 bcrypt는 입력값으로 72 bytes character를 사용해야 하는 제약이 있다.
scrypt는 PBKDF2와 유사한 adaptive key derivation function이다.
scrypt는 다이제스트를 생성할 때 메모리 오버헤드를 갖도록 설계되어, brute-force attack을 시도할 때 병렬화 처리가 매우 어렵다.
따라서 PBKDF2보다 안전하다고 평가된다. 미래에 bcrypt에 비해 더 경쟁력이 있다고도 여겨진다.
scrypt는 여러 프로그래밍 언어의 라이브러리로 제공받을 수 있다.
scrypt의 파라미터는 6가지이다.
DIGEST = scrypt(Password, Salt, N, r, p, DLen)
MD5, SHA-1, SHA-256 등의 해시 함수는 메시지 인증과 무결성 체크를 위한 것이다.
이런 것들을 패스워드 인증에 사용하면 인식 가능성과 빠른 처리속도에 기인하는 취약점이 발생한다.
이것을 해결하기 위해 key derivation function 사용을 고려할 수 있다.
위에 정리한대로 패스워드 암호화는 데이터베이스가 털릴 경우를 대비한 것이다.
burte force 공격에 대비하기 위해서 패스워드 암호화 알고리즘의 수행시간을 조절할 수 있어야 하고,
rainbow table를 방어하기 위해 랜덤 salt를 추가해야 한다.
위의 조건을 갖춘 패스워드 암호화 알고리즘으로 PBKDF2, bcrypt, scrypt 등이 있으므로 상황을 살펴 선택하면 된다.
ISO-27001의 보안규정을 준수하고, 서드파티의 라이브러리에 의존하지 않으면서도 사용자의 패스워드의 다이제스트를 생성하려면 PBKDF2- HMAC-SHA-256/SHA-512를 사용하면 된다.
일반적으로 규정을 준수해야하는 상황이며, 매우 강력한 패스워드 다이제스트를 생성하는 시스템을 쉽게 구현하고 싶으면 bcrypt를 사용하는 것이 좋다.
구현하는 시스템이 민감한 정보를 다루고, 보안 시스템을 구현하는데 많은 비용을 투자할 수 있다면 scrypt를 사용하면 된다.
https://junho94.tistory.com/30
https://hansoul.tistory.com/83
https://velog.io/@kylexid/%EC%99%9C-bcrypt-%EC%95%94%ED%98%B8%ED%99%94-%EB%B0%A9%EC%8B%9D%EC%9D%B4-%EC%B6%94%EC%B2%9C%EB%90%98%EC%96%B4%EC%A7%88%EA%B9%8C
http://www.codeok.net/%ED%8C%A8%EC%8A%A4%EC%9B%8C%EB%93%9C%20%EB%B3%B4%EC%95%88%EC%9D%98%20%EA%B8%B0%EC%88%A0