Bcrypt 암호화 방식 - Bcrypt amhohwa bangsig

Contents

bcrypt

bcrypt는 Blowfish를 기반으로 만들어진 "단방향 암호화 해싱함수"로 1999년 USENIX에서 발표됐다. Rainbow table 공격을 막기 위해서 salt를 사용하며, 암호검사 요청이 반복될 수록 cost를 늘림으로써, 무차별 대입 공격(brute-force search)을 막을 수 있다. cost는 반복횟수로 2^n 이다.

bcrypt 함수는 OpenBSD와 SUSE 리눅스를 비롯한 몇몇 리눅스 배포판에서 암호화 해시 알고리즘으로 사용하고 있다. 리눅스의 /etc/shadow 파일을 열어보면 "$2a$"나 "$2b$"로 시작하는 패스워드 해시가 있는데, 이들이 bcrypt 방식의 암호화 해시다.

  • $ : bcrypt의 오리지날 버전은 $2a$ : bcrypt의 오리지날 버전은 $2$다. 오리지날 버전은 non-ASCII 문자나 널 문자를 처리하는 방법을 정의하지 않았다. $2a$는 널 문자를 포함하며, UTF-8로 인코딩 할 것을 정의한 버전이다. . 오리지날 버전은 non-ASCII 문자나 널 문자를 처리하는 방법을 정의하지 않았다. 널 문자를 포함하며, UTF-8로 인코딩 할 것을 정의한 버전이다.
  • 10$ : Cost의 크기는 2^10이다. Iteration count를 1024만큼 돌리겠다는 얘기다.
  • N9qo8uLOickgx2ZMRZoMye : 랜덤하게 만든 salt
  • ljZAgcFl7p92ldGxad68LJZdL17lhWy : 패스워드. Salt와 패스워드를 묶어서 해시해버렸기 때문에, 유추가 불가능하다.

테스트 코드

package main import ( "fmt" "golang.org/x/crypto/bcrypt" ) var password = []byte("mypassword-123") func main() { // password로 부터, 암호화 해시를 만든다. // cost는 DefaultCost(10) en, _ := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost) fmt.Println(string(en)) // 패스워드를 비교한다. // 성공할 것이다. err := bcrypt.CompareHashAndPassword(en, []byte("mypassword-123")) if err != nil { fmt.Println("Error", err.Error()) } else { fmt.Println("Success") } // 패스워드를 비교한다. // 실패할 것이다. err = bcrypt.CompareHashAndPassword(en, []byte("mypassword-234")) if err != nil { fmt.Println("Error", err.Error()) } else { fmt.Println("Success") } }

참고

  • 안전한 패스워드 저장

안녕하세요. Azalbe 팀에서 웹 백엔드 개발을 담당하고 있는 도현입니다.

웹 서비스에서 비밀번호를 암호화하는 과정에 있어, 데이터를 저장하고 관리하는 데 기본적으로 암호화 처리를 진행하게 됩니다. 제가 프로젝트를 진행하면서, 암호화를 진행은 해왔는데, 이게 과연 안전한가에 대해 의문점이 들어, 암호화 방식에 관해 연구를 해봤습니다. 기존에 단순히 믿을만한 모듈을 사용하는 것을 넘어 분석을 진행해 보고 여러 모듈을 합쳐보았습니다. 그 방법을 소개해봅니다.

SHA 256, SHA 512이 안전할까 ?

//en.bitcoinwiki.org/wiki/SHA-256

암호화를 프로젝트에서 적용을 해왔는데, 개발자로서 “있는 모듈 쓰면 되는 거 아닌가?” 라는 생각으로 패스워드를 암호화하고 있었습니다. 처음에 SHA 512로 암호화를 했고, 똑같은 비밀번호를 사용했을 때 같은 다이제스트가 나오는 상황을 찾았습니다. 제 생각에 이는 굉장히 위험한데, 과연 이대로 쓰는 게 옳을까? 라는 생각을 하게 되었습니다.

관심있게 지켜본 주제

  • 레인보우 테이블 (rainbow table)?
  • salt 소금을 쳐라!
  • bcrypt 썼을때의 좋은 점은 무엇인가?
  • bcrypt 성능은 괜찮을까?
  • 단방향 암호화인 bcrypt 모듈 만으로 안전할까?
  • 양방향 알고리즘 AES 사용하기

레인보우 테이블(rainbow table) ?

레인보우 테이블이란 hash함수를 사용하여 만들어낼 수 있는 값들을 대량으로 저장한 표입니다. MD5 암호화가 쉽게 복호화될 수 있다는 것을 보여준 해킹기법 중 하나입니다. google에 rainbow table site를 검색해 보기만 해도 사이트가 나오고 있고, 해당 다이제스트를 복사해서 넣으면 평문이 나오게 됩니다.

salt! 소금을 쳐라!

// 기존의 암호화 방식
const crypto = require('crypto');
crypto.createHash('sha512').update('비밀번호').digest('base64');
// bcrypt 를 이용한 salt 방식
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(myPlaintextPassword, salt, function(err, hash) {
// Store hash in your password DB.
});
});

기존의 암호화 방식의 문제점

  • 똑같은 비밀번호로 암호화를 SHA 512로 처리를 했고 같은 다이제스트가 나오는 상황이 반복됩니다.
  • 이의 경우 기존의 비밀번호를 해커가 유저의 컴퓨터에서 훔쳐냈을때 같은 값을 대입하기만 하면 데이터베이스에 접근할 수 있는 상황이 되기 때문에 위험하다고 판단됩니다.

Salt를 쳤을 때 기존의 방식에서의 타협점

  • 레인보우 테이블 사이트가 많아지면서 salt로 hash화 하여 같은 값을 비밀번호로 사용해도 다른 hash화 된 패스워드가 생성됩니다.
  • 이는 해커의 해독 시간을 늦출 뿐만 아니라, 해시 함수 H 말고도 이 해시의 결과를 레인보우 테이블의 가능한 입력으로 변환해 주는 함수 R이 더 들어가게 됩니다. 물론 R은 입력에 따라 다르고, 해시 함수와는 달리 원래 가능한 입력에 적절히 대응만 되기만 하면 되기 때문에 관리가 용이합니다.

bcrypt 썼을때의 좋은 점은 무엇인가?

  • bcrypt 모듈은 사용자가 입력한 비밀번호를 hash화 하면서 데이터베이스에 앞부분에 salt 정보를 같이 저장하여 사용합니다. 따라서 password 컬럼 하나에 저장할 수 있어서 성능적으로 이점이 있을 것으로 보입니다.
  • bcrypt는 현재 가장 강력한 해시 알고리즘을 갖고 있으므로, blowfish 암호화를 해커가 복호화 하는데 있어 시간이 걸립니다. 따라서 해킹에 대비해서 암호화한 값을 알아내는 데 걸리는 시간을 늦출 수 있고 해킹에 대해서 이에 빠르게 대응할 수 있는 점이 장점이라 생각합니다.
  • SHA와 bcrypt가 비교가 많이 되는 듯 보입니다. SHA가 보안에 결함이 있기보단, SHA는 GPU연산에 유리한 32비트 논리 및 산술 연산을 이용하기 때문에, 해커가 빠른 연산으로 공격할 수 있기 때문입니다.
//stackoverflow.com/questions/56859377/bcrypt-and-salted-passwords-clarification

bcrypt 성능은 괜찮을까?

  • Cost factor는 2의 몇의 제곱으로 rounds를 돌릴 것인가 입니다. 이러한 부분들로 인하여 서버 과부하 문제가 발생할 수 있습니다. 서버 과부하 문제는 서버 측 모니터링을 통해서 지켜보고 rounds를 조절하여 맞추면 될 것 같습니다.

단방향 암호화인 bcrypt 모듈 만으로 안전할까 ?

  • 만약 DB가 해킹당했다고 가정을 해보자! salt와 salt로 hash 된 password 값이 같이 있는 DB 과연 안전할까? 서버 측에서 키를 .env파일에 가지고 있으면 보안에도 좋으므로 대칭키 암호화로 한 번 더 암호화를 하는 방법을 생각해 냈습니다.

양방향 알고리즘 AES 사용하기

  • AES 암호화는 양방향 알고리즘으로써 암호화와 복호화 과정에서 동일한 키를 사용하는 대칭키 알고리즘 입니다.
  • 진행 중인 프로젝트에서는 password를 프론트 쪽에서 볼 이유가 없어서 키를 전달할 필요가 없습니다. 이러한 이유로 서버에 키를 안전한 곳에 두고 패스워드를 복호화하여 true / false 체크 합니다. DB쪽에는 당연히 bcrypt로 salt를 이용한 암호화 된 값에 AES로 암호화를 한 번 더 거치기 때문에 DB가 해킹당한다 해도 안정성을 지니고 있다고 볼 수 있습니다.
//www.transcend-info.com/Embedded/Essay-15

Azalbe Team은 세상에 도전하고, 진짜 일을 하는 것을 두려워하지 않는 사람들입니다. 거친 여정을 위해 달려가는 팀에게 응원의 한마디는 큰 힘이 됩니다.

Toplist

최신 우편물

태그