crypto 모듈을 사용해서 암호화, 복호화 시키기
암호화 방법은 단방향 암호화와 양방향 암호화 두가지가 있습니다.
1. 단반향 암호화
비밀번호는 보통 단반향 암호화를 사용합니다. 단방향 암호화는 복호화를 할 수 없는 암호화 방식입니다.
복호화란 암호화된 문자열을 암호화 되기전의 문자열로 돌려놓는 것을 의미합니다. 그러므로 단방향 암호화를 사용하면 원래 문자열이 무엇인지 알 수 없습니다.
단방향 암호화를 사용하는 이유는 굳이 사용자의 비밀번호를 다시 복호화 할 필요가 없기 때문입니다.
DB에 저장되어있는 암호와 비교를 할 때는 단방향 암호화를 통해서 비교하면 되기 때문에 문제가 없습니다.
즉, 기존 비밀번호는 어디에도 남지 않고 암호화된 문자열로만 비교하는 방법입니다.
단방향 암호화는 해시 알고리즘을 사용합니다. 해시는 임의의 크기를 가진 문자열을 고정된 길이의 다른 문자열로 바꾸는 것을 말합니다.
해시 함수 사용하기 예
const password = 'onepassword'
const password2 = 'twopassword'
const base64crypto = password => {
console.log(plugins.crypto.createHash('sha512').update(password).digest('base64'))
}
base64crypto(password)
base64crypto(password2)
// password
UWo1TmcJr6ojrARyhC/er6ffsmnhkfXr4uuknTq+SEQqAghTPnClXmwENwJL3+6I6teJyqimDaaDYSH80TdqOA==
// password2
ZMlGJKKiGj9OJ/5tvE2atqA0edtAUP9C62Td3xh4+VY+KezMWwC/IoJGjQHeR3D25XmdJSxyxxB1xdh9XcXZIg==
위처럼 암호화된 문자열로 나오게 됩니다.
단방향 해시 함수의 문제점
단방향 해시 함수는 원본 문자열을 찾거나 동일한 효과의 문자열을 찾을 수 있습니다. 이와 같은 암호화된 문자열의 목록을 '레인보우 테이블'이라고 합니다.
이러한 문제점을 해결하기 위해 salting과 key strtching을 사용하여 보완합니다.
기존 문자열에 추가로 덧붙이는 문자열을 salt라고 합니다. 기존 문자열에 salt를 덧붙이고, 암호화된 문자열(다이제스트[digest])을 생성하는 것을 salting이라고 합니다.
기존 문자열의 다이제스트를 생성하고 생성된 다이제스트를 통해서 다시 다이제스트를 생성하는 방법을 '키 스트레칭(Key Stretching)'이라고 합니다.
이렇게 입력된 패스워드를 동일한 횟수 만큼 해시화 해야 입력한 패스워드와 암호화된 패스워드 일치여부를 확인 할 수 있습니다.
crypto는 randomBytes, pbkdj2 메소드를 지원합니다.
randomBytes, pbkdj2 메소드 사용 예
const password = 'onepassword'
const password2 = 'twopassword'
const base64crypto = password => {
plugins.crypto.randomBytes(64, (err, buf) => {
const salt = buf.toString('base64');
plugins.crypto.pbkdf2(password, salt, 100, 64, 'sha512', (err, key) => {
console.log(salt);
console.log(key.toString('base64'));
});
});
};
base64crypto(password)
base64crypto(password2)
// ZdhwgYgTUXqCBPIZSK8uIBwubTQh1cu0BCQpGBR33+JAF7gS97Krm4rU9lB68yPNqawFLWlKDa/ZaB60cR6Zxg==
// 6iiBdb49tJusPUbkxoeqO5ZMU/y0M9OZWyHqklEKZfe/TRKRsbG9jJucE3xUHUYSBcTP3x1umFJTlzdvgJNaEw==
// 5VdFDV0q/XBIQJ0RmkzM/xFz7tVwSXUvjffzSExrD4jKsFLRcSq2o2uh4FE9qsP+WIYDUV46dGP+N/VXj9Fevg==
// 2FHpJEGChf3dbTO2EQExdxSFY8C8mKmWscHNdfpRyKesPgabfruW7B88MUuOXYKwl9eJQYcc1AaTisu0r3g8Tw==
위처럼 randomBytes 메소드에서 64바이트 길이의 임의 문자열(salt)을 생성합니다. pbkdf2 메소드는 순서대로 비밀번호, salt, 반복 횟수, 출력될 바이트 수, 해시 알고리즘을 parameter로 받아서 처리합니다. 위는 키 스트레칭을 100번 반복한 것입니다.
pbkdf2 메소드는 간단하게 사용할 수 있지만, bcrypt나 scrypt보다 취약하기에 더 나은 보안이 필요할 경우 사용합니다.
:: 실행할 때마다 값이 다르게 출력되는 이유는 randomBytes를 통해 salt의 값이 매번 변경되기 때문입니다.
:: bcrypt : 패스워드 저장을 목적으로 설계되었습니다. openBSD에서 기본 암호 인증 메커니즘으로 사용되고 있습니다. 단 입력값이 72byte인 제약이 있습니다.
:: scrypt : pbkdf2와 유사하게 salting과 key Stretching을 반복하며, digest를 생성할 때 메모리 오버헤드를 갖게끔 설계가 되어 있어서 억지기법공격을 시도할 때 병렬화 처리가 어렵습니다.
양방향 암호화
양방향 암호화에는 대칭형 암호화와 비대칭형 암호화가 있습니다. 양방향 암호화는 암호화된 문자열을 기존 문자열로 복호화 할 수 있는 암호화 기법입니다. 암호화된 문자열을 복호화 하기 위해 암호화 할 때 사용했던 키와 같은 것을 사용해 주어야 합니다.
양방향 암호화 예
const password = 'onepassword'
const password2 = 'twopassword'
const key = 'helloworld';
const encoder = (password, key) => {
const encrypt = plugins.crypto.createCipher('des', key);
const encrypt2 = encrypt.update(password, 'utf8', 'base64') + encrypt.final('base64');
console.log(encrypt2);
return encrypt2;
}
const decoder = (password, key) => {
const decrypt = plugins.crypto.createDecipher('des', key);
const decrypt2 = decrypt.update(password, 'base64', 'utf8') + decrypt.final('utf8');
console.log(decrypt2);
}
const en = encoder(password, key);
decoder(en, key);
const de = encoder(password2, key);
decoder(de, key);
// kNiXXsNIwFCkNTJ5jyw5Hg==
// onepassword
// bYPMKWrEMSZup9dtg4VllA==
// twopassword
위 코드처럼 암호화 했던 문자열이 기본 문자열로 복호화 되는 것을 알 수 있습니다.
'NodeJS > NodeJS' 카테고리의 다른 글
[ NodeJS | EJS ] EJS 사용하기 ( Feat. json파일 불러오기 ) (0) | 2023.05.24 |
---|---|
[ NodeJS ] nodemailer 사용하기 (0) | 2022.11.30 |
[ NodeJS ] fs (0) | 2022.07.16 |
[ Node ] nodemon 사용하기 (0) | 2022.07.07 |
[ Node ] webpack 사용하기 (0) | 2022.07.03 |