본문 바로가기

TIL

5/30[TIL] 사용자의 비밀번호는 어떻게 저장하나요?

회원가입 및 로그인을 할 시 서버는

사용자의 비밀번호를 어떻게 저장하게 될까?

 

이 질문에 대한 답변은 2가지 정도가 있다고 볼 수 있다.

 

첫 번째 사용자가 입력한 것 그대로 저장하는 것과(Plain Text)

두 번째 사용자가 입력했던 것을 암호화해서 저장하는 것이다.

 

첫 번째처럼 한다면 정말 큰일이 아닐 수 없다. 이렇게 된다면 사용자의 정보가 손쉬운 먹잇감이 될 것이다. 이 것은 거의 범죄를 저지르는 것과 같다고 볼 수 있다. 얼른 두 번째 방법으로 수정해야 할 것이다.

 

두 번째 처럼 암호화해서 저장하는 경우에는 보통 단방향 해쉬 함수를 이용하게 되는데 이는 입력한 비밀번호를 수학적인 연산을 통해 변환하여 이 암호화된 비밀번호로는 원래 비밀번호를 알 수 없고 이를 단방향성이라고 이야기한다.

 

해쉬 알고리즘에는 많이 사용하는 SHA-256 등 많이 존재한다. 이렇게 SHA-256으로 인코딩 된 비밀번호를 저장하게 되면 사용자가 로그인 시에 비밀번호 입력하고 이를 해쉬 한 값을 저장된 값과 비교하여 일치 여부를 판단하게 하는 것이다.

 

원본의 내용이 약간만 변화되어도 해쉬 된 값은 완전히 달라져 원래 비밀번호를 어렵게 만든다. 하지만 이 것만으로는 안전하지 못하다.

 

단방향 해쉬 함수의 문제점을 알 수 있는데 해쉬 함수는 무결성 체크를 하기 위해서는 좋은 원리이다. 하지만 이 것이 어찌보면 암호화에서의 해쉬함수의 약점이 된다고도 생각한다. 해쉬 되기 전의 원본과 해쉬된 값은 인코딩하면 서로 항상 데이터 무결성의 강점처럼 결과 값이 원본 데이터와 해쉬된 데이터가 서로 같기 때문에 작정하고 해쉬 값을 다 찾아서 역대입을 다해버린다면 결국에는 입력한 비밀번호는 노출이 되고 말 것이다. 이러한 공격을 레인보우 공격이라고 하며 이러한 것들의 목록을 만든 것이 레인보우 테이블이라고 한다.

 

원래 해쉬 함수는 지금 암호화 관련해서 널리 사용되고 있지만 원래는 비밀번호를 저장하기 위해서 설계된 것이 아니라 짧은 시간의 데이터를 검색하기 위해 설계 된 것이라고 한다. 그렇기에 해쉬 함수의 빠른 처리 속도로 인해 공격하는 사람이 빠른 속도로 임의의 문자열과 해킹할 대상의 값을 비교할 수 있다.

 

이렇게 비교하게 되면 비밀번호가 길거나 복잡하지 않은 경우에는 비밀번호를 알아내는 데에 그리 큰 시간이 필요로 하지 않는다. 통상적으로 사용자들은 비밀번호를 길게 사용하지 않을뿐더러 복잡한 문자를 많이 조합하지도 않는다. 기억하기 쉬운 동일한 비밀번호를 사용하는 경우가 더욱이 허다하다.

 

사용자는 사이트에서 비밀번호를 인증하는데 걸리는 시간에 그리 민감하지 않다. 해쉬 함수의 장점인 빠른 속도에 사용자는 물론이고 공격자들도 편의성을 본의 아니게 가지게 된다. 

 

이런 단방향 해쉬 함수를 보완하기 위해서는 어떤 방법이 있을까?

먼저 솔팅(Salting)이 있다.

출처 : https://st-lab.tistory.com/100

솔트(Salt)는 단방향 해쉬 함수에서 해싱할 때 추가되는 바이트 단위의 작은 문자열이라고 보면 된다. 원본 값에 문자열을 추가하여 해싱 것을 솔팅(salting)이라 한다. 그렇게 되면 그럼 기존의 비밀번호와는 좀 더 복잡한 형태의 해쉬 함수가 나오게 되는데 어떤 Salt를 사용했는지 공격하는 측에선 알 수 없기 때문에, 레인보우 테이블을 만드는데 오래 걸리게 된다. 

 

두 번째로 Key Stretching(키 스트레칭)이 있다.

출처 : https://d2.naver.com/helloworld/318732

말 그대로 스트레칭, 쭉 늘린다는 뜻이다. 해시를 여러 번 반복하여 충분히 시간을 늘림으로써 무차별 대입 공격에 대비한다. 어떻게 시간을 늘리냐면, 패스워드의 다이제스트(해쉬 된 값)를 생성하고, 생성된 다이제스트를 입력 값으로 하여 다이제스트를 생성하고, 또 이를 반복(Iteration count)해서 다이제스트를 생성하는 식으로 늘린다. 보통 사용자가 작성한 패스워드가 짧거나 예측하기 쉬운 경우가 많은데 Key Stretching은 이를 더 어렵게 만들어 준다.

 

솔팅과 키 스트레칭으로 구성된 암호화 시스템을 구현하려면 이미 검증된 암호화 시스템을 사용하는 것이 좋다. 암호화 시스템을 잘못 구현해서 발생하는 위험을 피할 수 있다.

 

  • PBKDF2 : 가장 많이 사용되며 Django에서 기본으로 사용 중이다. 국제표준 정보보호 인증인 ISO-27001의 보안 규정을 준수하고 있다.
  • bcrypt : 애초부터 패스워드 저장을 목적으로 설계되어 매우 강력한 패스워드 다이제스트를 생성하는 시스템을 쉽게 구현할 수 있다. 관련된 라이브러리도 언어별로 쉽게 찾을 수 있다.
  • scrypt : 위 둘보다 진보된 시스템이다. 만약 구현하려는 시스템이 매우 민감한 정보를 다루고, 보안 시스템을 구현하는 데 많은 비용을 투자할 수 있다면 사용한다.

 

참고출처: https://d2.naver.com/helloworld/318732