디비에 비번 저장하기

Alex Xu라는 분이 만든 bytebytego 유튜브 채널에 올라온 영상이다: https://www.youtube.com/watch?v=zt8Cocdy15c&ab_channel=ByteByteGo


Alex Xu는 System Design Interview (https://www.amazon.com/System-Design-Interview-insiders-Second/dp/B08CMF2CQF)라는 책을 쓴 사람인데 인터뷰 준비하는 사람들에게 리뷰가 좋은 책이고 올라온 영상들과 블로그 포스팅들을 보니 설명이 아주 잘 돼있어서 올라오는 것마다 이렇게 필기할 생각이다.


비번은 민감한 정보이다. 때문에 우리는 디비가 외부로 노출되더라도 피해를 최소화할 수 있도록 해야 한다.


비번을 저장할 때 절대 하지 말아야 할 것은 plain text(평문)로 저장하지 않는 것이다. 비번을 저장하는 두 가지 방법이 있는데 한 가지 방법은 OWASP 가이드라인이 제시하는 Hash 함수를 사용하는 방법과 다른 한 가지 방법은 비번을 암호화하여 저장하는 방법이다.


먼저 비번을 암호화하는 방법은 많이 쓰이지 않는다. 암호화의 단점은 암호화 키를 알게 되면 복호화가 가능하다는 점이다. 물론 암호화 키와 알고리즘을 알아내기란 쉽지 않다. 하지만 나날이 발전하는 컴퓨터의 성능과 해커들의 기술로 인해 암호화가 뚫리는 시간이 점점 짧아지고 있다. 


Hash란?

Hash란 어떠한 알고리즘을 통해 기존 값을 무작위 형태로 변환하는 것이다. 


private void calcHash(int original) {

return original % 13;

}

위의 함수는 original 정수를 13으로 나눈 나머지를 반환한다. 아주 간단한 hash 함수다. 간단한 만큼 문제가 있다. 13으로 나누다 보니 중복이 발생할 확률이 아주 높다. 실제 비번이 1이라 할지라도 14를 입력하면 같은 값이 나오기 때문에 보안에 약하다. 이 함수를 강화하기 위해서 13 대신에 더 큰 숫자를 쓸 수도 있지만 결국엔 같은 문제에 직면하게 된다.


암호화와의 차이점은 hash 된 비번으로 기존 값을 알아낼 수가 없다는 것이다. 때문에 디비가 노출되어도 hash 함수의 원리를 알지 못하는 이상 무용지물의 데이터가 된다.


그럼 어떻게 안전한 hash 함수를 만들 수 있을까? 개발자의 좋은 점은 내가 생각하는 대부분의 것들은 이미 다른 사람들이 다 구현해놓아서 우리는 가져가 쓰기만 하면 된다.


대표적으로 MD5, SHA-1가 있는데 속도는 빠르지만 구글이 collision(충돌) 면에서 취약하다는 문제를 제기했다. 또한 hash 함수라고 무조건 안전한 게 아니다. Precomputation attack을 통해 아주 짧은 시간에 무력화될 수도 있다. 


SHA-1 대체제로 SHA-2나 SHA-3을 쓸 수도 있지만 좀 더 강력한 bcrypt 함수가 있다.


bcrypt의 속도는 좀 더 느리지만 보안면에선 훨씬 뛰어나다.


기존 hash 함수는 비번을 그대로 input으로 사용한다면, bcrypt는 각 비번마다 고유한 salt값을 비번에 더한 후 계산한다.


예로

비번 = Hello

Salt = World

Hash 함수 input = HelloWorld

Hash 함수 output = 18vn3kaurkasdad3gd (무작위값)