개발 학습 실습실

이 사이트의 실습은 자바스크립트를 켜야 움직입니다. 아래는 같은 내용을 글로 적은 것입니다.

공부 › 보안 › 인증

비밀번호 해시

DB가 털렸을 때 비밀번호는 얼마나 버티나

회원 두 명이 우연히 같은 비밀번호(password123)를 씁니다. 비밀번호를 DB에 저장하는 방식에 따라, DB가 유출됐을 때 공격자가 원래 비밀번호를 알아내는 데 걸리는 시간이 크게 달라집니다. 해시는 원래 값으로 되돌릴 수 없게 계산해 낸 값입니다. 평문, 해시, 솔트를 넣은 해시, 일부러 느리게 만든 해시(bcrypt)를 비교합니다.

일부만 실행으로 확인 · SHA-256은 실제 계산, bcrypt는 재지 못함

이 실습에 나오는 개념

해시 함수와 솔트
해시 함수는 입력을 고정된 길이의 값으로 바꾸는 함수로, 결과에서 원래 입력을 되돌릴 수 없다. 비밀번호는 원문 대신 해시 값을 저장해 유출되더라도 원문이 드러나지 않게 한다. 솔트는 비밀번호마다 다르게 덧붙이는 무작위 값으로, 같은 비밀번호라도 다른 해시가 되게 해 미리 계산해 둔 해시 목록을 이용한 공격을 막는다.
bcrypt
비밀번호 저장용으로 설계된 해시 함수다. 솔트를 자동으로 생성해 결과에 포함하고, 연산 비용(cost)을 설정해 일부러 계산을 느리게 만든다. 계산이 느리면 공격자가 수많은 후보를 대입해 보는 데 드는 시간이 크게 늘어난다. Spring Security의 BCryptPasswordEncoder가 이를 사용한다.
대칭키 암호화와 비대칭키 암호화
대칭키 암호화는 암호화와 복호화에 같은 키를 쓰는 방식으로 빠르지만 키를 상대와 안전하게 공유해야 하는 문제가 있다(AES). 비대칭키 암호화는 공개키와 개인키의 쌍을 쓰는 방식으로, 공개키로 암호화한 것은 개인키로만 풀 수 있어 키 공유 문제가 없지만 느리다(RSA). 실제로는 비대칭키로 대칭키를 안전하게 교환한 뒤 대칭키로 데이터를 암호화한다.

이렇게 바꿔 보세요

처음 설정으로 실행하면

  1. 회원 김철수와 이영희가 가입하면서 둘 다 비밀번호를 password123으로 정했습니다. 서버가 SHA-256 방식으로 DB에 저장합니다.
  2. 두 회원의 저장값이 완전히 같습니다. DB를 본 사람은 두 사람의 비밀번호가 같다는 것을 바로 알 수 있고, 하나를 알아내면 같은 값을 가진 모든 회원의 비밀번호를 알게 됩니다.
  3. 사고: 공격자가 DB의 회원 테이블을 통째로 빼냈습니다.
  4. 해시는 거꾸로 계산할 수 없지만, 흔한 비밀번호의 해시를 미리 계산해 둔 표가 이미 존재합니다. 공격자는 저장값을 표에서 찾기만 하면 됩니다. password123의 SHA-256은 누구에게나 같은 값이기 때문입니다.
  5. 흔한 비밀번호 1억 개를 회원 한 명에게 모두 대입해 보는 데 걸리는 시간: 1초 미만. password123처럼 흔한 비밀번호는 사실상 즉시 찾아냅니다.

실행 결과

코드

MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(rawPassword.getBytes(UTF_8));
member.setPassword(HexFormat.of().formatHex(hash));

이 모형의 전제

SHA-256 값은 실제로 계산한 값입니다. bcrypt 저장값은 형식을 보이기 위한 예시 문자열입니다. 대입 속도는 대략적인 크기를 나타냅니다. 고성능 그래픽 카드 한 장 기준으로 SHA-256은 초당 수백억 번, bcrypt cost 10은 초당 수천 번 수준이라고 보았고, 공개된 벤치마크의 자릿수에 맞춘 값입니다. 로그인 검증 시간도 서버 CPU에 따라 달라지는 어림값입니다. 스프링 시큐리티의 BCryptPasswordEncoder 기본 cost는 10입니다. 이 PC에서 openssl로 잰 SHA-256 속도는 CPU 코어 하나로 초당 약 3,200만 번이었습니다(화면의 초당 수백억 번은 그래픽 카드 기준의 공개 수치입니다). bcrypt는 이 PC에 라이브러리가 없어 실제로 재지 못했습니다.

앞 실습: 쿠키 · 다음 실습: JWT의 구조와 검증

이 실습에 나오는 개념

이 실습에서 보는 것

설정

코드


      
    

그림

실행 비교

이렇게 바꿔 보세요