많은 웹사이트에서 비밀번호를 찾기를 진행할 경우 새로운 비밀번호를 입력하는 상황을 자주 보았을 것이다. 이것은 데이터베이스에 비밀번호를 저장하지 않아서 웹서버도 비밀번호를 모르기 때문이다. 데이터베이스에 비밀번호를 저장할 때 보안상의 이유로 비밀번호를 바로 저장하지 않고 HASH 암호화된 값을 저장한다. 이번 문서에서는 사용자의 비밀번호를 암호화하는 방법에 대해 알아보자!
먼저 Hash 암호화의 특징에 대해 간단히 알아보자
hash암호화는 단방향 암호화 기술이다. 암호화가 적용되기 전인 평문을 암호화된 문장으로 변경해 주는데 다시 이 암호화된 문장을 평문으로 변경할 수는 없다. hash 암호화의 특징은 다음과 같다.
- 해시 알고리즘은 종류가 다양하며,그 알고리즘은 모든 사람에게 공개되어있다. 심지어 해커에게도!
하지만 앞에서 말했듯 암호화된 평문을 다시 평문으로 복호화는 불가능하다.
- 해시 알고리즘마다 Hash 길이가 다르고 이미 보안이 뚫린 해시 함수가 존재한다.
따라서 MD5, SHA-1, HAS-180은 사용하면 안된다. 보안이 인증된 SHA-256, SHA-512 등을 사용해야 한다.
- 해시 알고리즘은 특정 입력 대해 항상 같은 해시 값을 리턴한다.
이 점을 이용해서 우리는 비밀번호 인증을 진행할 것이다. 어떤 입력인지 몰라도 해시함수를 이용해서 해시된 값이 일치하면 입력이 같다는 것이 입증된다.
우리가 사용할 모듈은 node.js 내장 모듈중 crypto
이다.
먼저 crypto 모듈을 불러오자.
const crypto = require('crypto');
hash를 사용하기 전에 salt를 먼저 생생해야 한다. salt는 랜덤으로 생성된 난수 값으로 rand()와 비슷한 의미를 가지고 있다. 하지만 rand()는 의사난수 생성기로 보안이 완벽하지 않아 salt로 추천하지 않는다.
아래 코드를 통해 crypto 모듈에서 난수를 생성한다.
const salt = crypto.randomBytes(128).toString('base64');
이제 생성한 salt값을 이용하여 해시 암호화를 진행하자.
inputPassword는 사용자가 입력한 비밀번호이다.
const hashPassword = crypto.createHash('sha512').update(inputPassword + salt).digest('hex');
해시 암호화의 결과인 암호문과 salt값은 모두 데이터베이스에 저장되어야 로그인 시 인증이 가능하다. 전체 코드로 합치면 다음과 같은 함수가 작성된다.
app.post('/Signup', async function (req, res, next) {
const body = req.body;
const inputPassword = body.passwd;
const salt = crypto.randomBytes(128).toString('base64');
const hashPassword = crypto
.createHash('sha512')
.update(inputPassword + salt)
.digest('hex');
connection.query(
'INSERT INTO user_table (user_id, user_salt, user_passwd) values (?,?,?)',
[body.id, salt, hashPassword],
function (err, rows, fields) {
if (err) {
console.log('sign_up error', err);
res.send(false);
} else {
res.send(true);
}
},
);
});
로그인의 경우에도 signup과 동일하게 사용자가 입력한 비밀번호를 암호화한다. 사용자가 암호화한 결과와 데이터베이스에 저장된 결과를 비교하여 비밀번호가 일치하는지 판단하여 로그인을 결정하면 된다.