단방향 해시 함수

Nam Eun-Ji·2020년 11월 26일
2
post-custom-banner

보통 패스워드를 DB에 저장할 때 두 가지 방법으로 저장한다.

  • 단순 텍스트
  • 단방향 해시 함수의 다이제스트
    단순텍스트로 저장하는 것은 공격이 들어와 털리면 그대로 뚫리기 때문에 법으로도 막고 있다.


단방향 해시 함수

해시 함수는 입력값을 문자와 숫자를 임의로 나열한 일정한 길이의 다이제스트(Digest)형태로 변환시켜준다. 여기서 다이제스트란, 해시함수를 통해 생성된 암호화된 메시지이다. 해시 함수는 단방향이므로 암호화는 가능하지만 복호화는 불가능하여 원본을 알 수 없기 때문에 이와 같은 이유로 패스워드를 바로 데이터베이스에 저장하지 않고 단방향 암호화된 다이제스트를 저장하는 것이 보편화되었다.




단방향 해시 함수 문제점

레인보우 공격(rainbow attack) - 인식 가능성
동일한 메시지가 언제나 동일한 다이제스트를 갖는다면 해커가 전처리(pre-computing) 된 다이제스트를 다량 확보한 다음 탈취한 다이제스트와 비교해 원본 메시지를 찾아내거나 동일한 효과의 메시지를 찾을 수 있다. 이와 같은 다이제스트 목록을 레인보우 테이블(rainbow table)이라 한다. 게다가 다른 사용자의 패스워드가 같으면 다이제스트도 같으므로 한꺼번에 모두 정보가 탈취될 수 있다.

무차별 대입 공격(brute force attack) - 속도
해시 함수는 원래 짧은 시간에 데이터를 검색하기 위해 설계된 것으로 해시함수의 빠른 처리 속도로 인해 해커는 매우 빠른 속도로 임의의 문자열의 다이제스트와 해킹할 대상의 다이제스트를 비교할 수 있다. (MD5를 사용한 경우 일반적인 장비를 이용하여 1초당 56억 개의 다이제스트를 대입할 수 있다)




단방향 해시 함수 보완

솔팅(Salting)
패스워드에 임의의 문자열인 salt를 추가하여 다이제스트를 생성하는 것으로, 같은 패스워드라도 각기 다른 salt가 들어가 다이제스트가 다르게 생성되어 rainbow table을 무의미하게 만든다. salt는 최소 128bit 정도는 되어야 안전하다.

키 스트레칭(key stretching)
해시를 여러 번 반복하여 시간을 늘림으로써 무차별 대입 공격(brute force attack)에 대비하는 것이다. 쉽게 말하자면, 패스워드의 다이제스트를 생성하고, 생성된 다이제스트를 입력값으로 하여 또 다이제스트를 생성하고.. 이를 반복하여 다이제스트를 생성하는 식이다. 만약 원래대로라면 1초에 56억 개를 대입하여 비교할 수 있는데 키스트레칭을 적용하여 1초에 5번 정도만 비교할 수 있게 설정한다면 하나의 다이제스트를 해킹하는 데 오랜 시간이 걸릴 것이다.




해시 함수 종류

  • MD5, SHA-1, HAS-180 : 이미 보안이 뚫린 해시 함수들

  • SHA-256, SHA-512 : 특정 입력값에 대해 항상 같은 해시 값을 리턴(레인보우 어택에 취약)

  • PBKDF2(Password-Based Key Derivation Function)
    해시함수의 컨테이너인 PBKDF2는 솔트를 적용한 후 해시함수의 반복 횟수를 임의로 선택할 수 있다. PBKDF2는 아주 가볍고 구현하기 쉬우며, SHA와 같이 검증된 해시함수만을 사용한다.(Django에서 사용)

  DIGEST = PBKDF2(PRF, Password, Salt, c, DLen)

  # PRF: 난수(예: HMAC)
  # Password: 패스워드
  # Salt: 암호학 솔트
  # c: 원하는 iteration 반복 수
  # DLen: 원하는 다이제스트 길이
  • bcrypt (Key Derivation Functions)
    bcrypt는 처음부터 패스워드 저장을 위해서 설계되었다. bcrypt는 보안에 집착하기로 유명한 OpenBSD에서 기본 암호 인증 메커니즘으로 사용되고 있고 미래에 PBKDF2보다 더 경쟁력이 있다고 여겨진다. 입력값을 72byte로 해야 하는 부분이 PBKDF2와 scrypt와 다르다.

  • scrypt (Key Derivation Functions)
    scrypt는 상대적으로 최신 알고리즘이며 나머지 둘보다 더 경쟁력 있는 것으로 평가되나 아직 덜 확산되어 있다. scrypt는 다이제스트를 생성할 때 메모리 오버헤드를 갖도록 설계되어, brute force attack을 시도할 때 병렬화 처리가 매우 어렵다. 따라서 PBKDF2보다 안전하다고 평가되며 미래에 bcrypt에 비해 더 경쟁력이 있다고 여겨진다. scrypt는 보안에 아주 민감한 사용자들을 위한 백업 솔루션을 제공하는 Tarsnap에서도 사용하고 있다.

DIGEST = scrypt(Password, Salt, N, r, p, DLen)  

# Password: 패스워드
# Salt: 암호학 솔트
# N: CPU 비용
# r: 메모리 비용
# p: 병렬화(parallelization)
# DLen: 원하는 다이제스트 길이



사용자 인터페이스 고려 사항

  • 패스워드의 길이를 제한 두지 않는다.(길이 제한을 둔다면 평문 저장이 의심될 뿐만 아니라 brute force의 범위를 좁힐 수 있기 때문)
  • 최소 길이는 제한하는 것이 좋다.
  • 특수문자, 대소문자를 제한하지 않는다.
  • 패스워드(민감한 정보)를 입력하는 POST 요청은 반드시 SSL로 보낸다.
  • 패스워드 실패 회수 제한을 걸어놓는다.

참고하면 좋을 글 - 비밀번호 해시에 소금치기 - 바르게 쓰기

profile
한 줄 소개가 자연스러워지는 그날까지
post-custom-banner

1개의 댓글

comment-user-thumbnail
2021년 9월 1일

해당 내용을 정리 해놓은 곳을 찾고 있었는데 핵심만 잘 요약해주신것 같습니다. 감사합니다!

답글 달기