React
[React] crypto 를 이용하여 암호화 하기 - 떽떽대는 개발공부
떽이
2021. 2. 24. 19:19
웹페이지 구현 중 회원가입 부분을 코딩하던 중 암호화 하는 부분이 있어 포스팅 한다.
암호화는 crypto 를 이용하여 단방향 암호화를 해줄 것이다.
클라이언트에서 암호화 해서 서버로 전달하는 방법을 찾았지만 아직까지 소득이 없어.. 서버 쪽에서 암호화 해서 db 에 저장하는 방식으로 진행할 것이다.
아래와 같이 서버단에서 전달받은 parameter 에 암호화를 해주고 그 안에서 db 전달 쿼리를 작성하였다.
const express = require('express');
const router = express();
const db = require('../config/db');
const crypto = require('crypto');
const util = require('util');
router.post('/join_ing', (req,res) => {
crypto.randomBytes(64, (err, buf) => {
//salt는 생성하는 해시값 이외에 추가적인 암호화 값
const salt = buf.toString('base64');
console.log('salt :: ', salt);
//crypto.pbkdf2의 salt 뒤 숫자 파라미터는 임의의 값으로 주어준다.
crypto.pbkdf2(req.query.cust_pw, salt, 1203947, 64, 'sha512', (err, key) => {
console.log('password :: ', key.toString('base64')); // 'dWhPkH6c4X1Y71A/DrAHhML3DyKQdEkUOIaSmYCI7xZkD5bLZhPF0dOSs2YZA/Y4B8XNfWd3DHIqR5234RtHzw=='
// 클라이언트로부터 전달받은 params 확인
console.log(`= = = > req : ${util.inspect(req.query)}`)
// 쿼리 작성하여 전달
const sql = 'INSERT INTO `cust_inform` (`cust_no`, `cust_id`, `cust_pw`, `cust_salt`, `cust_name`, `cust_phone`, `cust_email`, `cust_fulladdress`, `cust_extraaddress`, `cust_postcode` ) VALUE ( (SELECT ifnull(max(`cust_no`), 0) + 1 as `cust_no` from `cust_inform` A) , ? , ?, ? , ? , ? , ? , ? , ? , ? )'
const param = [req.query.cust_id, key.toString('base64'), salt, req.query.cust_name, req.query.cust_phone, req.query.cust_email, req.query.cust_fulladdress, req.query.cust_extraaddress, req.query.cust_postcode]
db.query(sql, param, (err, data) => {
if(!err) {
res.send(data)
} else {
res.send(err)
}
})
});
});
})
module.exports = router;
위와 같이 작성하면 서버로부터 전달 받은 req.query 값은 아래와 같다.
클라이언트로부터 전달받은 pw 는 'qwer1234' 이지만 password :: 쪽을 보면 암호화 되어 알수없는 문자로 변환 되었다.
이제 변환된 비밀번호와 salt 값도 함께 db 에 입력해주면 된다.
**중요한 점은 이 변환된 비밀번호와 변환할 때 생성했던 salt 값 모두 db 에 함께 넣어 주어야 한다는 점이다. 나중에 salt 값으로 로그인 확인을 할 수가 있다.
// 비밀번호를 확인할 때는 같은 salt 값, 반복 횟수, 비밀번호 길이, 해시 알고리즘, 인코딩 방식 모두 동일해야 함
crypto.pbkdf2('입력비밀번호', '기존salt', 1203947, 64, 'sha512', (err, key) => {
console.log(key.toString('base64') === '기존 비밀번호');
});
위의 코드를 이용하여 로그인 시 비밀번호를 확인해보자.
클라이언트로부터 위와 같이 id와 비밀번호를 전달 받았다.
router.post('/login_ing', (req,res) => {
console.log(`= = = > req : ${util.inspect(req.query)}`)
const sql = 'SELECT ifnull(`cust_pw`, NULL) AS `cust_pw`, ifnull(`cust_salt`, NULL) AS `cust_salt` FROM `cust_inform` RIGHT OUTER JOIN (SELECT "") AS `cust_inform` ON `cust_id` = ?'
const param = [req.query.cust_id]
db.query(sql, param, (err, data) => {
if(!err) {
if(data[0].cust_salt !== null){
crypto.pbkdf2(req.query.cust_pw, data[0].cust_salt, 1203947, 64, 'sha512', (err, key) => {
console.log('비밀번호 일치 여부 :: ', key.toString('base64') === data[0].cust_pw);
// true : 아이디, 비밀번호 일치
// false : 아이디 일치, 비밀번호 불일치
res.send({ result : key.toString('base64') === data[0].cust_pw })
});
} else {
// null : 아이디 불일치
res.send({ result : data[0].cust_salt })
}
} else {
res.send(err)
}
})
})
mySQL 에 전달받은 id 값으로 비밀번호와 salt 값을 찾는다.
rowdata 값이 0 일 경우 값이 return 되지 않으므로 outer join 을 사용하였다.
만약 db 에 일치하는 값이 없다면 (등록된 아이디 없음) null 로 받을 것이고, 있다면 salt 값과 비밀번호를 받아와서 비교하여 결과값을 전달한다.