Home Server - 06
Post
X

Server - 06

비밀번호 암호화

참고 글 : crypto,로그인 페이지 만들기 - 07


비밀번호 암호화 함수

32 Byte의 임의의 문자열을 salt로 만들고 crypto의 pbkdf2Sync 메서드를 사용해 암호화합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 암호화된 비밀번호 생성 함수
const createPasswordAndSalt = (userInputPassword) => {
  try {
    const salt = crypto.randomBytes(32).toString("base64");

    const key = crypto
      .pbkdf2Sync(userInputPassword, salt, 200, 8, "sha512")
      .toString("base64");

    return `${key}$${salt}`;
    // 암호화된 비밀번호와 임의로 생성된 salt를 '$'로 구분합니다.
  } catch (err) {
    throw err;
  }
};

비밀번호 검증 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 비밀번호 검증 함수
// 사용자의 입력 값과 데이터베이스에 저장된 암호화된 값을 비교해 검증합니다.
const userPasswordVerify = (userInputPassword, storedPasswordAndSalt) => {
  try {
    const [encrypted, salt] = storedPasswordAndSalt.split("$");

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

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

crypto.util.js

src폴더 안에 utils폴더를 만들고 crypto.util.js파일을 작성합니다.

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
import crypto from "crypto";

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

    // 매개변수 : 입력값, salt, 반복 횟수, Key의 길이, 해시알고리즘
    const key = crypto
      .pbkdf2Sync(userInputPassword, salt, 200, 8, "sha512")
      .toString("base64");

    return `${key}$${salt}`;
    // 암호화된 비밀번호와 임의로 생성된 salt를 '$'로 구분
  } catch (err) {
    throw err;
  }
};

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

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

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

export { createPasswordAndSalt, userPasswordVerify };

암호화 적용

user.controller.js 파일을 수정합니다.

  1. 회원가입 시, 암호화된 비밀번호를 DB에 저장합니다.

  2. 로그인 시, DB에서 가져온 암호화된 비밀번호를 검증 함수를 사용해 입력 값과 비교합니다.

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
import userStorage from "../models/user.model.js";
import {
  createPasswordAndSalt,
  userPasswordVerify,
} from "../utils/crypto.util.js";

export default {
  login: async (req, res, next) => {
    let response = {};

    try {
      let { id, password } = req.body;

      const user = await userStorage.getUserInfo(id);

      if (!user) {
        response = {
          success: false,
          msg: "아이디가 존재하지 않습니다",
        };
      } else {
        // 비밀번호 검증
        let checkedPassword = await userPasswordVerify(password, user.password);

        if (checkedPassword) {
          response = {
            success: true,
            msg: "로그인 성공",
          };
        } else {
          response = {
            success: false,
            msg: "비밀번호가 틀렸습니다",
          };
        }
      }

      res.json(response);
    } catch (err) {
      next(err);
    }
  },

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

    try {
      let { id, password } = req.body;

      const checked = await userStorage.checkUser(id);

      if (checked) {
        response = { success: false, msg: "이미 존재하는 아이디입니다" };
      } else {
        // 암호화된 비밀번호 생성
        req.body.password = await createPasswordAndSalt(password);

        // DB에 새로운 사용자 등록
        await userStorage.createUser(req.body);

        response = { success: true, msg: "회원가입 완료." };
      }

      res.json(response);
    } catch (err) {
      next(err);
    }
  },
};
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.