패스워드 암호화

markus·2021년 7월 11일
0

Youtube Clone

목록 보기
7/16

유저의 비밀번호를 그대로 DB에 저장하는 것은 위험하다. 따라서 암호화해서 저장할 필요가 있다.

Hash Function

유저의 비밀번호가 123이라 가정하자. 해쉬함수는 "123"을 "8QuI2rgKIm0cAuH0uTLkKKASkR2X51su"와 같이 바꿔주는 함수이다.

가정한 것임. 실제로 바뀌는 값과 다름.

특징

  1. 동일한 입력값에 대해서는 항상 동일한 결과값이 나온다.
    "123"을 입력하면 항상 "8QuI2rgKIm0cAuH0uTLkKKASkR2X51su"의 결과값을 가진다.

  2. 입력값이 약간만 바뀌어도 결과값은 매우 다르게 출력된다.
    "123"의 출력값과 "1234"의 출력값은 어마무시하게 다르다.

  3. 해쉬함수는 단방향 함수이다.
    "123"을 입력하면 "8QuI2rgKIm0cAuH0uTLkKKASkR2X51su"을 얻을 수 있지만 역의 경우는 성립하지 않는다.


✅ 해쉬함수를 통해 바뀐 값을 DB에 저장해야 안전하다.

Key Stretching, Salt

그러나 해쉬함수만으로는 안전하게 비밀번호를 저장할 수 없다. 특징 1번 때문이다. 구글에 해쉬함수를 검색해서 123을 입력하면 그에 대한 해쉬함수값을 바로 알 수 있다. 이렇게 해쉬함수의 입력에 대한 결과값을 모아놓은 리스트가 있는데 이것을 "레인보우 테이블" 이라고 한다.

  1. Key Stretching은 해쉬함수를 여러 번 돌리는 작업이다.
    예를 들어, 3번 수행한다고 가정하자.

    "123" ---> "8QuI2rgKIm0cAuH0uTLkKKASkR2X51su" (1번)
    "8QuI2rgKIm0cAuH0uTLkKKASkR2X51su" ---> "Nd07AoqqlBtozMMU3A6ABW4WgJLeHSub" (2번)
    "Nd07AoqqlBtozMMU3A6ABW4WgJLeHSub" ---> "2SGApMywq2vbfpJ0XSjLQRfROcFcWeLv" (3번)

    최종적으로 "2SGApMywq2vbfpJ0XSjLQRfROcFcWeLv"가 결과값이 된다. 물론, 레인보우 테이블을 통해 알아낼 수 있겠지만 알아내려면 시간이 제법 소요된다.

  2. Salt는 '유저가 입력한 패스워드 + 임의의 값'을 해쉬함수 입력값으로 넣는 방법이다.

    유저가 "123"이라는 패스워드를 입력했고 salt가 "9XoRVMqU3jUjUs6aIECu9uD9WHdtUAJ7"을 임의의 값으로 주었다고 가정하자.
    그러면 해쉬함수에는 "1239XoRVMqU3jUjUs6aIECu9uD9WHdtUAJ7"이 입력값으로 들어가게 된다. 123의 결과값을 레인보우 테이블이 가지고 있더라도 임의의 값 때문에 유추하기 어려워진다.

Bcrypt

만약 key stretching과 salt를 둘다 사용해서 해쉬함수로 돌리면 어떨까? 아마 알아내기 무척 어려워지지 않을까? bcrypt는 이 둘을 모두 사용해서 비밀번호를 암호화한다.

사용방법

userSchema.pre("save", async function () {
  if (this.isModified("password")) {
    this.password = await bcrypt.hash(this.password, 5);
  }
});

기타

pre는 DB에 저장되기 전에 실행되는 mongoose의 middleware이다. 위의 코드인 경우, "Document.prototype.save()"이 실행될 때 pre함수가 호출된다. async/await를 사용하면 next()를 생략할 수 있다.


Reference

0개의 댓글