비밀번호가 유출됐다는 소식을 들으면 대개 일회성 사고로 받아들인다. 어느 서비스가 운이 나빴고, 기사가 났고, 비밀번호를 바꿨고, 그걸로 끝. 끝이 아니다. 유출된 날은 무언가의 마지막 날이 아니다. 앞으로 몇 년을 굴러갈 조립 라인의 첫날이고, 그 라인 위에서 당신의 이름은 단 한 번도 불리지 않는다. 이 이야기는 처음부터 끝까지 해둘 만하다. 거의 아무도 전 과정을 보지 못하기 때문이다.
1단계: 누군가 데이터베이스를 통째로 꺼낸다
시작은 전혀 극적이지 않다. 누군가 SQL 인젝션 하나를 찾아낸다. 열려 있는 백업 파일을 찾아낸다. 기본 계정이 그대로 살아 있는 관리자 패널을 찾아낸다. 그리고 테이블 하나를 들고 나간다.
그 테이블에는, 운이 좋으면 당신의 이메일과 비밀번호 해시가 들어 있다. 운이 덜 좋으면 당신의 이메일과 비밀번호가 들어 있다. 평문으로. 당신이 입력한 그대로.
2009 평문 비밀번호 3,200만 개
2009년 12월, 소셜 네트워크용 위젯을 만들던 RockYou라는 회사가 SQL 인젝션을 당했다. 비밀번호 약 3,200만 개가 통째로 빠져나갔고, 깨야 할 해시 같은 건 없었다. 평문으로 저장하고 있었으니까.
RockYou에게는 재앙이었고, 나머지 모두에게는 선물이었다. 실제 비밀번호로 이뤄진 거대한 말뭉치가 처음으로 존재하게 된 것이다. 누가 읽을 거라고는 상상도 못 한 사람들이 직접 쓴 것들. 연구 자료가 아니라 실물 그 자체.
이 파일은 rockyou.txt가 되었고, 지금도 공격을 시험할 때 기준이 되는 사전으로
쓰인다. 이 파일의 가치는 당신의 비밀번호가 그 안에 있다는 데 있지 않다. 사람들이
비밀번호를 어떻게 쓰는지가 들어 있다는 데 있다. 이름 하나에 연도 하나, 단어
뒤에 123, 마지막에 !. RockYou가 흘린 건 3,200만 개의 비밀이 아니다. 패턴을
흘린 것이다. 그리고 패턴에는 유효기간이 없다.
2단계: 깰 수 있는 건 깬다, 전혀 서두르지 않고
여기서 직관이 어긋난다. 누군가 서비스의 로그인 화면에서 당신의 비밀번호를 맞혀 보려 하면 서비스가 끊어버린다. 세 번 틀리면 CAPTCHA, 그다음엔 잠금. 서버를 상대로 하는 추측은 느리고 시끄럽다.
이미 자기 디스크에 들어 있는 해시 파일을 상대로는 서버가 없다. 안 된다고 말해줄 사람이 반대편에 아무도 없다. 로컬에서, GPU로, 시도 횟수 제한 없이, 세상의 모든 시간을 들여 돌린다. 서비스가 해싱을 엉망으로 했다면 — 빠른 알고리즘에, 솔트도 없이 — 평문과의 차이는 보안의 차이가 아니라 편의의 차이일 뿐이다.
게다가 무작위로 넣어보지도 않는다. 먼저 rockyou.txt, 그다음엔 거기서 뽑아낸
규칙들. a를 @로 바꾸기. 끝에 연도 붙이기. 당신이 기발하다고 생각했던 모든
잔재주는 이미 10년 넘게 설정 파일 안에 적혀 있다.
그렇게 해서 덤프의 일부가 읽을 수 있는 비밀번호로 바뀐다. 나머지 — 길고, 무작위고, 어떤 사전에도 없는 것 — 은 여전히 잡음으로 남는다. 검사기가 긋는 선이 바로 이 선이다. 잔소리를 하는 게 아니라, 당신이 어느 쪽에 떨어지는지 알려준다.
3단계: 대조한다, 그리고 여기서 당신은 돈이 된다
덤프 하나만으로는 값이 별로 안 나간다. 값나가는 건 집계다. 서로 다른 사이트의
유출 열 건을 가져와 이메일로 대조하고, 이미 평문으로 풀린 이메일:비밀번호 쌍만
남긴다. 그 결과물을 콤보 리스트라고 부르는데, 이건 더 이상 누구의 데이터베이스도
아니다. 사람들의 명단이다.
2013 재고 목록이 공개되다
2013년 12월, 트로이 헌트(Troy Hunt)가 Have I Been Pwned를 시작했다. 유출에 등장한 이메일 주소를 모아둔 공개 데이터베이스로, 누구나 자기가 그 안에 있는지 물어볼 수 있게 한 것이다. 밑에 깔린 발상은 단순하고 또 불편하다. 공격자가 이미 재고 목록을 갖고 있다면, 피해자에게 그걸 감추는 건 아무도 지켜주지 않는다. 몇 년 뒤에는 Pwned Passwords가 나왔다. 비밀번호를 대상으로 같은 일을 하되, 비밀번호를 보내지 않고도 조회할 수 있다. 해시의 앞 일부만 보내면 서버가 후보 묶음을 돌려주는데, 서버는 그중 어느 것이 당신 것인지 알지 못한다.
2017 NIST가 특수문자 대신 목록을 요구하기 시작하다
NIST가 SP 800-63B를 내놓으면서, 가입 양식을 지배하던 정설 대부분을 배 밖으로 던져버렸다. 그리고 그 자리에 아무도 예상하지 못한 요구사항 하나를 앉혔다. 비밀번호를 설정할 때 시스템은 그것을 알려진 유출 값 목록과 대조해야 하고, 목록에 있으면 거부해야 한다는 것.
세부사항의 변경이 아니라 이론의 변경이다. 이제 질문은 당신의 비밀번호가 강해 보이는지가 아니라, 이미 공개되어 있는지다. 그래서 생성기는 유일하게 말이 되는 일을 한다. 한 번도 있어본 적 없는 곳에서 비밀번호를 꺼내오는 것.
2019 이미 다른 유출들의 재탕이었던 유출
2019년 1월, Collection #1이라는 이름으로 유명해진 묶음이 돌아다녔다. 헌트가 분석해서 그 안에 든 것을 세어봤다. 고유한 이메일 주소 약 7억 7,300만 개, 평문 상태의 고유한 비밀번호 약 2,100만 개. 수천 개 출처에서 긁어모은 것이었다.
중요한 건 규모가 아니었다. 어디서 나왔느냐였다. 상당 부분이 이전 유출들을 재탕한 것으로, 이미 크래킹까지 끝나 쓰기 편한 형식으로 정리돼 있었다. 물론 헌트는 그때까지 파악하지 못했던 자료도 함께 발견했다. 상품은 침입이 아니었다. 재고 목록이었다. 그리고 그런 재고 목록의 용도는 단 하나뿐이다.
크리덴셜 스터핑: 아무도 당신을 노리지 않는다
당신을 공격하는 사람은 없다. 이게 좀처럼 받아들여지지 않는 대목이다.
아무도 앉아서 당신의 계정을 생각하지 않는다. 누군가 수억 줄짜리 콤보 리스트를 가져와, 은행이나 메일 서비스의 로그인 폼에 그걸 하나씩 넣어보는 도구에 밀어 넣고, 차단에 걸리지 않도록 시도를 여러 IP 주소로 나눠 뿌린 다음, 기다린다. 압도적 대다수는 실패한다. 상관없다. 비용이 거의 안 드니까.
이게 크리덴셜 스터핑이고, 이건 추측이 아니다. 확인이다. 비밀번호는 이미 갖고 있다. 알아내는 건 그걸 또 어디에 썼는지뿐이다.
그 옛날 커뮤니티 게시판 비밀번호는 중요하지 않았다. 그 게시판도 중요하지 않았다. 중요한 건 그 똑같은 문자열이 당신의 메일함을 열고, 메일함이 “비밀번호 찾기”를 통해 나머지 전부를 연다는 사실이다. 원죄는 그게 약했다는 게 아니다. 같은 것이었다는 점이다. 서른 자짜리 무작위 완벽한 비밀번호도 두 사이트에 돌려쓰면 그 둘 중 더 나쁜 쪽만큼만 안전하다. 그리고 더 나쁜 쪽이 해싱을 어떻게 하는지는 당신이 어쩌지 못한다.
여기서 나오는 결론
- 유출된 비밀번호를 바꾸는 것만으로는 부족하다, 돌려썼다면. 급한 건 뉴스에 나온 그 사이트가 아니다. 나머지들이다.
- 사이트마다 하나씩, 잊어버려도 아무렇지 않을 것으로. 비밀번호를 전부 외울 수 있다면, 개수가 너무 적거나 질이 너무 나쁘거나 둘 중 하나다.
- 2단계 인증은 이 사슬을 끊는다. 크리덴셜 스터핑이 시험하는 건
이메일:비밀번호다. 그것만으로 들어갈 수 없다면 재고 목록은 값어치를 잃는다.
유출된 당신의 비밀번호는 적의 손에 들려 있지 않다. 파일의 어느 한 줄에, 다른 수억 줄 사이에 끼어, 누군가 사이트 하나 더 시험해볼 만하다고 판단할 때까지 기다리고 있다. 그리고 그게 통할지 말지를 정한 사람은, 몇 년 전 같은 단어를 두 번째로 입력한 당신이다.
출처: RockYou 유출(2009년 12월)과 이후 공격 사전으로 쓰이게 된 rockyou.txt ·
트로이 헌트의 Have I Been Pwned와 Pwned Passwords · 유출된 값 목록과 비밀번호를
대조하는 문제를 다룬 NIST SP 800-63B · Collection #1에 대한 트로이 헌트의
분석(2019년 1월)과 그가 공개한 수치 · OWASP의 크리덴셜 스터핑 정의.