ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Password hashing] Argon2, Bcrypt, Scrypt, PBKDF2 소개
    Node.js/nest.js 2023. 3. 6. 23:34

    Springboot를 사용하면서 비밀번호 해싱은 늘 BcryptPasswordEncoder만 복사 붙여넣기 형태로 사용했다.

    Nest.js는 반면에 bcrypt, bcrypt.js, Scrypt, Argon2 등 passwordHash로 검색하면 나오는 라이브러리가 많아서 직접 알아봐야하는 상황이 있었다. 


    Spring Security의 공식 문서를 살펴보니 bcrypt, Scrypt, Argon2, Pbkdf2 등.. 다양하게 제공하고 있었다.
    이참에 자세히 알아보자.

    https://docs.spring.io/spring-security/reference/features/authentication/password-storage.html 
     
    Bcrypt가 무엇이고, 어떤 것을 사용하는 것이 좋은지 정리해본다.
     
    결론부터 말하자면 MD5, SHA1, SHA-256, SHA-512는 사용하면 안되고, 가능하면 Argon2를 사용하자.
    (특수 분야가 아닌 이상 계속 bcrypt 사용해도 2023년 지금은 괜찮은 것 같다.)

    비밀번호 암호화 하는 이유

    • 인터넷 통신은 보안성이 보장되지 않기 때문에 해커나 악의적인 사용자가 비밀번호를 가로챌 가능성이 크다.
    • 따라서, 비밀번호를 암호화하여 보안성을 높이는 것이 중요하다.

    해시(Hash)란?

    • 해시란 원형문자(plaintext)가 해시함수(해시 엔진)를 통과하여 암호화되어 나온 결과물
    • 해시함수(해시엔진)를 통과하는 과정을 **해싱(hashing)**이라고 한다.
    • 13 곱하기 29 가 무엇인지 누가 물으면 377 이라는 것을 금방 알 수 있다. 하지만 반대로 몇과 몇을 곱하면 377이 나오냐라고 물어보면 무수히 많은 경우의 수 가 있다.  이것이 해싱의 기본원리 이다.

    해싱(Hashing)의 단점

    • 원형문자가 같으면 해시 값도 같다.
      • ex) md5라는 해시 엔진을 통과한 12345라는 비밀번호의 hash는 무조건 ”*827ccb0eea8a706c4c34a16891f84e7b”*이다. (비밀번호 정책이 존재하는 이유 !!)
      • 이러한 해싱의 단점을 보완하기 위하여 플레인 텍스트에 랜덤의 문자열을 더 해준 뒤(salting) 해싱을 한다. 그리고 반복해서 여러번 암호화 하는 것을 Bcrypt가 수행한다.
    • Hashing된 값을 복호화할 수 없기 때문에, 개인정보 유출 시 해싱 된 비밀번호가 그대로 노출될 위험이 있다.

    Bcrypt

    • 1999년 등장한 해싱 알고리즘으로 24년간 안전하게 사용되고 있다.
    • 위에 언급한 salting 해싱 반복하는 기술이 동작원리다.

    Scrypt

    • 2009년 등장 Bcrypt 보다 설계를 개선했다. (특히 메모리 hardness <- 비전공자에게 이해하기 힘든 워딩...)
    • 공격자가 메모리를 더 사용하게 해서 공격시 Bcrypt 공격의 4000배 비용이 든다고 한다.

    Argon2

    • 2012~2015년 Password Hashing Competition 우승한 암호화 세계의 강자 argon2
    • bcrypt와 PBKDF2와 같은 아직 해싱 대표주자를 사용하기에도 무리 없지만, Argon2 발전하는 비밀번호 크래킹 기술에 대응하기 위해 등장했다.
    • 무어의 법칙에 따르면 10년이 지나면 CPU, GPU 성능 개선이 해싱을 decode하기 더 쉽게 만들 것이고, MD5, SHA1, SHA-256, SHA-512 같은 알고리즘은 1초면 크래킹 될 것이라고 한다.
    • 미래를 위해 등장한 해싱 알고리즘이다.

    사용법

    • 설치하기

    https://www.npmjs.com/package/argon2

    npm i argon2
    
    • passwordEncoder 구현
    import * as argon from 'argon2';
    
    export class PasswordEncoder {
      static encode(password: string): Promise<string> {
        return argon.hash(password);
      }
    
      static async compare(
        rawPassword: string,
        encodedPassword: string,
      ): Promise<boolean> {
        return await argon.verify(encodedPassword, rawPassword);
      }
    }
    
    • 로그인 컨트롤러
    async signup(request: UserSignUpRequestDTO) {
        const passwordHash = await PasswordEncoder.encode(request.password);
        return this.userRepository.save(request.toUser(request, passwordHash));
    }
    

    Java 에서도 Argon2를 사용할 수 있다.
    Reference 자바 Argon2 참조

    Reference

    반응형
Designed by Tistory.