사용자의 패스워드는 전송 과정에서 노출되지 않아야 하고, 서버에 저장할 때도 원문을 알아낼 수 없는 형태로 보관해야 합니다. 패스워드를 안전하게 전송하고 보관하는 기본 방법을 정리해 보겠습니다.

패스워드 전송 방법

클라이언트는 사용자가 입력한 패스워드 원문을 서버에 전달하고, 서버가 이를 검증합니다. 이때 평문 HTTP를 사용하면 네트워크 구간에서 패스워드가 그대로 노출될 수 있으므로 반드시 HTTPS(TLS)를 사용해야 합니다.

즉, 애플리케이션이 서버에 전달하는 값은 원문 패스워드이지만 실제 네트워크 구간에서는 TLS로 암호화됩니다. 클라이언트에서 패스워드를 단순히 해시한 뒤 전송하는 것만으로는 충분하지 않습니다. 해당 해시값 자체가 패스워드처럼 재사용될 수 있기 때문입니다.


패스워드 보관 방법

서버는 전달받은 패스워드를 데이터베이스에 평문으로 저장하지 않고 단방향 해시 함수를 사용해 만든 다이제스트를 저장합니다.

해시

해시는 원본 데이터를 일정한 길이의 완전히 다른 값인 다이제스트(digest)로 변환하는 과정입니다. 단방향 함수이므로 다이제스트에서 원본 패스워드를 복호화할 수 없습니다.

로그인할 때는 사용자가 입력한 패스워드에 가입 당시와 같은 방식의 해시 연산을 적용한 뒤, 저장된 다이제스트와 비교합니다.

하지만 단순한 해시 함수만 사용하면 공격자가 가능한 패스워드를 빠르게 대입하는 브루트 포스 공격(무차별 대입 공격)에 취약할 수 있습니다. 이를 보완하기 위해 키 스트레칭과 솔팅을 함께 사용합니다.

키 스트레칭

키 스트레칭(key stretching)은 해시 연산을 의도적으로 여러 번 반복하거나 계산 비용을 높여 다이제스트를 만드는 방법입니다. 한 번의 검증에 필요한 시간을 늘려 공격자가 짧은 시간 안에 많은 패스워드를 대입하기 어렵게 만듭니다.

솔팅

솔팅(salting)은 패스워드마다 생성한 임의의 문자열인 솔트(salt)를 원문 패스워드에 추가한 뒤 해싱하는 방법입니다. 같은 패스워드를 사용하는 사용자라도 서로 다른 다이제스트가 만들어지므로 미리 계산된 해시 목록을 이용하는 레인보우 테이블 공격을 방어하는 데 도움이 됩니다.

솔트는 비밀값일 필요가 없으므로 다이제스트와 함께 저장할 수 있지만, 사용자마다 충분히 무작위인 값을 새로 생성해야 합니다.

실제 구현에서는 일반 해시 함수만 직접 반복하기보다 솔트와 키 스트레칭을 지원하는 Argon2id, bcrypt, scrypt, PBKDF2 같은 전용 패스워드 해시 함수를 사용하는 것이 좋습니다.


한 줄 요약

패스워드는 HTTPS를 통해 서버로 안전하게 전송하고, 서버에서는 솔트와 키 스트레칭이 적용된 단방향 해시로 변환하여 보관합니다.

참고

Categories:

Updated: