Home 로그인 페이지 만들기 - 07 (crypto)
Post
X

로그인 페이지 만들기 - 07 (crypto)

Crypto 모듈을 이용해 비밀번호를 암호화해보자.


비밀번호 암호화

crypto 모듈을 이용해 비밀번호를 암호화해서 DB에 저장해보겠습니다.

먼저 미들웨어로 모듈화해 회원가입 시 사용자가 입력한 비밀번호를 암호화하는 함수로그인 시 사용자가 입력한 비밀번호를 검증하는 함수를 작성합니다.

이후 Controller에서 Model에 접근하기 전 모듈을 불러와 비밀번호를 변환한 후 작업하도록 수정해보겠습니다.


암호화 및 검증 함수

utils 폴더에 crypto_util.js 파일을 만들어 모듈화해 사용하겠습니다.

  • createPasswordAndSalt 함수
    회원가입 시 사용자가 입력한 비밀번호(password)를 인자로 받아 Salt + $ + Key 문자열로 반환하는 함수
    • Salt : 임의로 생성된 문자열
    • Key : crypto 모둘의 pbkdf2Sync 메서드로 생성한 암호화된 비밀번호 문자열
  • userPasswordVerify 함수
    사용자가 입력한 비밀번호 (userInputPassword)DB에 저장된 암호화된 비밀번호 (PasswordAndSalt)를 비교하는 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// utils/crypto_util.js
import crypto from "crypto";

// 암호화된 비밀번호 생성 함수
const createPasswordAndSalt = (password) => {
  try {
    const salt = crypto.randomBytes(64).toString("base64");

    const key = crypto
      .pbkdf2Sync(password, salt, 104906, 64, "sha512")
      .toString("base64");

    return `${key}$${salt}`;
    // 암호화된 비밀번호와 임의로 생성된 salt를 '$'를 기준으로 이어줍니다.
  } catch (err) {
    throw err;
  }
};

// 비밀번호 검증 함수
// 사용자의 입력 값과 데이터베이스에 저장된 암호화된 값을 비교해 검증합니다.
const userPasswordVerify = (userInputPassword, PasswordAndSalt) => {
  try {
    const [encrypted, salt] = PasswordAndSalt.split("$");

    const userInputEncrypted = crypto
      .pbkdf2Sync(userInputPassword, salt, 104906, 64, "sha512")
      .toString("base64");

    if (userInputEncrypted === encrypted) {
      return true;
    } else {
      return false;
    }
  } catch (err) {
    throw err;
  }
};

export { createPasswordAndSalt, userPasswordVerify };

Controller 수정

Controller에서 model에 요청하기 전 비밀번호를 암호화합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import UserStorage from "../models/model_user.js";
import {
  createPasswordAndSalt,
  userPasswordVerify,
} from "../utils/crypto_util.js";

const output = {
  ...
};

const process = {
  login: async (req, res) => {
    let response = {};

    try {
      const user = await UserStorage.getUserInfo(req.body.id);

      if (user) {
        let checkedPassword = await userPasswordVerify(req.body.password, user.password);

        if (checkedPassword) {
          // 로그인 성공 했을 때
          req.session.isLogined = true;
          req.session.name = user.name;

          return (response = { success: true });
        }

        return (response = { success: false, msg: "비밀번호가 틀렸습니다." });
      }

      response = { success: false, msg: "존재하지 않는 아이디입니다." };
    } catch (err) {
      // 간단한 에러 처리문 작성
      response = {
        success: false,
        msg: "로그인을 할 수 없습니다.\n잠시 후 다시 시도해주세요.",
      };
    } finally {
      res.json(response);
    }
  },

  register: async (req, res) => {
    let response = {};

    try {
      const user = await UserStorage.getUserInfo(req.body.id);

      if (user) {
        return (response = { success: false, msg: "아이디가 존재합니다." });
      }

      // 사용자가 입력한 비밀번호를 createPasswordAndSalt 로 암호화합니다.
      req.body.password = await createPasswordAndSalt(req.body.password);

      response = await UserStorage.createUser(req.body);
    } catch (err) {
      // 간단한 에러 처리문 작성
      response = {
        success: false,
        msg: "회원가입을 할 수 없습니다.\n 잠시 후 다시 시도해주세요.",
      };
    } finally {
      res.json(response);
    }
  },

  logout: (req, res) => {

    ...

  },
};

export default { output, process };

crypto-rds

데이터베이스에 암호화된 비밀번호가 담겨있는 것을 확인할 수 있습니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.