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 };
데이터베이스에 암호화된 비밀번호가 담겨있는 것을 확인할 수 있습니다.