Nodejs

비밀번호 암호화

와칸다개발자 2021. 9. 2. 19:43

사용자의 비밀번호는 디비에 곱게 암호화 해서 저장해야 합니다. 

안그러면 범죄입니다. (진짜 범죄인걸로 알고있음)

생각해보면 옛날에 웹사이트 비밀번호를 잊어버려 찾을 때 비밀번호를 그대로 

알려준 기억이 나는군요... 요즘은 다 비밀번호 바꾸라고 하죠 잡소리가 짧았습니다.

 

단방향 vs 양방향

 

단방향은 암호화는 가능 복호화 불가능

양방향은 복호화도 가능

 

웹사이트에서 비밀번호는 복호화할 이유가 없습니다. 

단방향은 Hash 알고리즘을 사용합니다. 평문을 고정된 길이로 변경합니다.

 

https://emn178.github.io/online-tools/sha256.html

 

SHA256 Online

 

emn178.github.io

여기서 어떤 길이의 평문을 입력해도 고정된 길이를 뱉어냅니다.

 

암호화 하기

const crypto = require('crypto');
const plaintext = 'password';

const cryptostr = crypto.createHash('sha512').update('plaintext').digest('base64');
console.log(cryptostr)

createhash는 사용할 암호화 알고리즘을 넣고

update 암호화할 평문을 넣어줍니다.

digset은 어떤 인코딩 방식으로 할지 정해줍니다.

 

근데 이렇게만 작성하면 안됩니다.

 

같은 평문에 대해서 같은 결과값이 나오기 때문에 해커들은 이를 데이터화해서

대략 이런 평문이구나 유추할 수 있습니다. 이를 레인보우 테이블이라 합니다.

Salt

salt 즉 소금을 뿌려주어 기존 암호화 문자열에 새로운 문자열을 수만번 해시화 합니다.

간단히 작성해 봅시다.

const crypto = require('crypto');

const createSalt = () => {
  return new Promise((reslove, reject) => {
    crypto.randomBytes(64, (err, buffer) => {
      if (err) {
        reject(err);
      } else {
        reslove(buffer.toString('base64'));
      }
    })
  });
}

const cryptoPassword = (plaintext, salt) => {
  return new Promise((reslove, reject) => {
    crypto.pbkdf2(plaintext, salt, 82824, 64, 'sha512', (err, key) => {
      if (err) {
        reject(err);
      } else {
        reslove(key.toString('base64'));
      }
    });
  });
}

const getCryptoPassword = async(plaintext) => {
  const salt = await createSalt();
  return await cryptoPassword(plaintext,salt);
}

여러번 반복해서 같은 평문이라도 다르게 나오는지 확인해 보겠습니다.

 

getCryptoPassword('plaintext').then(console.log);
getCryptoPassword('plaintext').then(console.log);
getCryptoPassword('plaintext').then(console.log);

 

다르게 나오는걸 확인할 수 있습니다.

그럼 함수를 살펴보겠습니다.

소금을 생성하는 함수를보면 randomBytes() 메소드로 64바이트 길이의 salt를 생성합니다.

그 다음 pbkdf2라는 메소드를 사용합니다. 인자가 많군요...........................

 

  1. 평문
  2. salt
  3. 반복횟수
  4. 비밀번호 길이
  5. 암호화 알고리즘

key라는 버퍼형태로 리턴해주기 떄문에 base64로 인코딩합니다.  

반복횟수는 불규칙하게 적당히 하세요. 찾아보니 반복횟수가 높으면 슈퍼컴퓨터로도

레인보우테이블을 생성하기 힘들다네요. ^^

 

그 다음 salt와 key를 둘 다 저장해줘야 합니다. salt를 생성하는 함수는 매번 다른 

salt를 뱉어댑니다. 함수이름도 그래서 random이 들어가겠져

 

새로 유저가 등록한다면 소금을 쳐서 비밀번호를 DB에 삽입하고

로그인한다면 db에 있는 소금으로 암호화해서 비번이랑 같은지 확인하시면 됩니다.