개요 사용자의 비밀번호를 그대로 보관하는 것은 위험하다. 비밀번호 보관에 특화된 bcrypt 를 알아보자. 참고링크 - 링크: https://auth0.com/blog/hashing-in-action-understanding-bcrypt/ - 링크: https://d2.naver.com/helloworld/318732 TL;DR - 빠르게, 보안도 신경썼다는 티를 내면서 구현하려면 bcrypt 를 사용하자 - 보안에 좀더 민감한 곳이라면 scrypt 를 쓰자 - 현 시점 비밀번호 저장의 끝판왕은 Argon2id 이다. 비밀번호를 보관하자. 1) Plaintext 를 저장한다면 데이터베이스가 털리면 바로 끝이다. - 이녀석 비밀번호는 asdf1234 이구나. 2) Hashing 을 한번 해주고 그걸 저장하면 낫지만 rainbow table 을 이용한 공격을 한다면? - 미리 많이 쓰는 비밀번호와 그 hash 값들을 테이블로 만들어놓으면, - 유출된 hash 값에서 비밀번호을 역으로 찾아낼 수 있다. 참고링크: http://bit.ly/36z3ujp 1) Dictionary attack: 많이 쓰는 비밀번호를 하나씩 넣어보자 2) Brute force attack: 사용가능한 문자열 내에서 무작위로 넣어보자 3) Rainbow Table: 위에 이미 언급 3) 비밀번호에 Salt 를 추가한 다음 hashing 하자 - salt 만들기와 hashing 이 한방에 이루어지면 금상첨화 SHA 가 있는데 bcrypt 는 왜 만들었지? SHA2, SHA3 는 너무 빠른게 오히려 단점이다. - 빨리빨리 rainbow table 을 만들 수 있다. - 최신 CPU, GPU라면 SHA-256 을 초당 백반, 천만번씩 수행할 수 있다. 한계들 1) constant password length: 잉간이 기억하고 쓸 수 있는 비밀번호라면 길이의 한계를 가진다. 2) rapidly evolving hardware: 컴터가 빨라진다고 해싱 속도가 빨라지면 난감하다. bcrypt 는 key setup phase 라는 일종의 막대한 전처리 요구로 느리게 만든 Blowfish 란 녀석의 특징에 반복횟수를 변수로 지정가능하게 하여 작업량 (=해싱시간) 을 조절할 수 있게 해주었다. → 원하는 만큼 속도를 조절가능한 hash 함수란 말이다. bcrypt 동작 원리 이미지 출처 : https://auth0.com/blog/hashing-in-action-understanding-bcrypt/ 1단계: Key setup phase eksblowfish 함수 - expensive key schedule Blowfish, Blowfish 의 key setup algorithm 강화버전이다. - 파라미터는 원하는 비용 (= 연산량, 소요시간), salt, password - password 를 가지고 key stretching 하며 연산속도도 늦춰줌 2단계: Operation phase - plaintext ↔ ciphertext 로 encrypt/decrypt 하는 단계 1) OrpheanBeholderScryDoubt 는 192 비트 (= 24 바이트) 이며 1단계의 결과이다. 2) 이걸 eksblowfish 가 동작하는 ECB mode 로 64번 암호화한다. 3) 암호화 루프 64번의 결과 + salt 128 비트 (=16 바이트) 등을 합친 것이 최종 결과이다. - 아래 예시를 보면 이해가 쉬울 것이다. 결과 해시 알아보기 온라인에서 bcrypt 로 암호화를 해보았다. 링크: https://www.devglan.com/online-tools/bcrypt-hash-generator 1) $2b 는 bcrypt 의 버전정보이다. 2) $10 은 10 round 를 의미하며, cost 정보를 의미한다. 이게 클 수록 연산의 cost 가 증가하는 것이다. 3) 까지가 cost 정보를 통해 생성된 salt 이다. 이 값은 매 실행시마다 변한다. 4) 나머지가 hash 값이다. 이 결과물은 1) preimage attack (역상공격) 에 대해 저항성을 가진다. http://bit.ly/2RSFhPC - 해시함수의 출력값이 같은 새로운 입력값을 찾는 공격 2) 충분히 큰 salt 공간을 가지고 있어서 rainbow attack 에 저항성을 가진다. 3) 변경이 가능한 cost (연산량, 연산시간) 실전을 통해 알아보기 - node.js 의 bcrypt 패키지를 이용하면 salt 생성과 hash 생성을 분리해서 볼 수 있어서 이해에 도움이 된다. - 코드는 링크에 나와 있다. https://auth0.com/blog/hashing-in-action-understanding-bcrypt/ 우선 cost 가 소요시간에 미치는 영향을 테스트 해보았다. 1) node.js. 설치 2) npm install bcryptjs 로 패키지 설치 3) 아래 코드 작성 후 node bcrypt1.js 실행 코드를 잠깐 보자 1) bcryptjs 라는 패키지를 가져온 다음 2) 비밀번호를 asdf1234 로 가정했다. 3) bcrypt.hashSync() 함수를 실행하는데 - 파라미터는 plainTextPassword 와 10 부터 20까지의 saltRounds 값이다. - 즉 cost 인 salt round 를 바꿔가며 소요시간을 측정해본 것이다. 결과를 보면 cost 가 10일때는 0.1초도 안되던 시간이 cost 를 20으로만 주어도 62초가 넘게 걸리는 것을 알 수 있다. → cost 가 30이 넘어가면 웬만한 시스템에서는 1년이 넘어 걸릴 수도 있다. 이러한 결과값으로 방정식을 역으로 만들어서 운영하는 시스템에 적절한 cost 를 계산해낼 수 있다. 이것 만으로도 불안하다면 정답은 two-factor, 혹은 multi-factor 인증이다. salt 와 hash 분리해서 만들어보기 1) saltRounds 값을 10으로 하여 bcrypt.genSalt() 함수로 salt 를 만들었다. - $2a$10$h3a5Cw4Amac.LDNjOWLAQu - bcrypt 버전은 $2a 이니 2a 이고 - saltRounds 는 $10 이니 10 rounds 란걸 알 수 있다. → 중요한 것은 매번 실행시마다 salt 값이 바뀐다는 것! 2) bcrypt.hash() 함수에 plainTextPassword 와 salt 를 넣어서 hash 를 만들었다. - hash 앞부분에 salt 가 포함되어 있는 것을 알 수 있다. Salt: $2a$10$DTKVAPansJtga9/d.K770e Hash: $2a$10$DTKVAPansJtga9/d.K770eSgvzoh/mW.1vMrd0FzzHArYlqaTQT9m Salt: $2a$10$z7wcUjnXVMGoaURjXmgvXO Hash: $2a$10$z7wcUjnXVMGoaURjXmgvXOQe65u0NnEaEDLWP7hGlSopyUgAVc342 한방에 hash 를 만들어보자 코드에 따로 설명이 필요할 것 같지는 않다. 아래와 같이 매 실행시마다 salt (=Hash 앞부분)과 전체 결과가 바뀌는 것을 알 수 있다. Hash: $2a$10$IzweIEGkW4A1uzMNnPH/GegLN8bAb2dXe7Gg9QKDFmzIQ9gvTuQYK Hash: $2a$10$uz0MJWTUvwQtdYertA9ibe/R0LOh9s1eH/3zxdev8vDzRgiLoqDgK Hash: $2a$10$krPc1D50B0XR6E1PGvSZ8eoPAvKc9yqH3HwCJzUtCbhGq57gixEPC 위 코드와 이 코드를 보면 무엇을 알 수 있을까? 1. 이 코드처럼, plainTextPassword 와 saltRounds 만 넣으면 hash 를 생성해서 저장해둘 수 있다. 2. 이제 이렇게 등록된 사용자가 비밀번호를 넣어 로그인을 시도한다면? 1) 입력한 비밀번호와 저장된 비밀번호 hash 의 앞 salt 로 hash 를 만들어보면 비밀번호가 맞는지 확인할 수 있겠지? 실제 validate 를 해보자 plainTextPassword 는 asdf1234 로 하고 hash 는 위에서 생성한 $2a$10$IzweIEGkW4A1uzMNnPH/GegLN8bAb2dXe7Gg9QKDFmzIQ9gvTuQYK 를 써보자 참고. Golang bcrypt 링크: https://godoc.org/golang.org/x/crypto/bcrypt 링크만 보아도 hash 생성과, 이후 입력된 비밀번호와의 비교를 알 수 있다. |