2022. 3. 17. 18:48ㆍBACK END/NODE.JS
bcypt는 블로피시 암호에 기반을 둔 암호 해시 함수로서 Niels Provos와 David Mazières가 설계하였으며 1999년 USENIX에서 발표되었다. 레인보 테이블 공격 방지를 위해 솔트를 통합한 bcrypt는 적응형 함수의 하나이다. 시간이 지남에 따라 속도 저하를 위해 반복 횟수가 증가가 수반될 수 있으므로 연산 파워의 증가에도 브루트 포스 검색 공격에 대한 저항을 유지하게 된다.
비밀번호를 안전하게 보관하기
위처럼 비밀번호를 Plaintext로 저장해둔다면 특정 상황에서 데이터베이스가 뚫릴 경우 보안상의 큰 위험을 초래하게 된다. Hashing을 한 번 해주고 저장하면 조금은 보안성을 갖출 수 있지만 rainbow table 등의 위협에서 아직 자유롭지 못하다. 그래서 비밀번호에 Salt를 추가한 다음 hashing을 해줄 필요가 있다.
1) Dictionary attack: 많이 쓰는 비밀번호를 하나씩 넣어보자
2) Brute force attack: 사용가능한 문자열 내에서 무작위로 넣어보자
3) Rainbow Table: 많이 쓰는 비밀번호와 그 hash값을 테이블로 만들어 놓고 유출된 hash값에서 암호를 역추적
Bcrypt의 장점
SHA를 암호해싱에 사용하는 암호화 함수들은 GPU를 이용한 공격에 취약하며(SHA family는 연산속도가 매우빠르기 떄문) 많은 메모리를 필요로 하지 않는 점을 문제로 지적하고 있다.
SHA가 보안에 결함이 있어서가 아니라 GPU연산에 유리한 32비트 논리 및 산술 연산만 사용하기 때문에, 공격자 역시 빠른 연산으로 접근할 수 있다. Bcrypt는 이런 문제로 SHA가 아닌 Blowfish를 이용하여 암호화 암수를 구현하였다.
이상적으로 봤을 때 한계가 없는 연산 능력을 가진 공격자는 모든 암호화 알고리즘을 해독할 수 있겠지만, 어디까지나 이론일 뿐이며 실제 공격자는 컴퓨터 자원을 무제한으로 보유하지 않기 때문에 공격자의 연산 속도를 늦추는 것으로 해독을 어렵게 만들 수 있다.
공격자의 시도 횟수가 충분할 때 방어자는 좀 더 느리게 해독될 수 있는 암호화 방식에 의존하는 것이 낫다.
Bcrypt 적용하기
1. bcrypt 모듈 설치
npm install bcrypt --save
터미널에서 위 명령어를 통해 프로젝트 폴더 경로에 설치해준다.
위 게시글에 의하면 bcrypt는 node-gyp 모듈에 의존성을 지니고 있다함. 하여 bcyrptjs를 사용함으로써 종속성에서 해방될 수 있다고 함..
npm i bcryptjs --save
npm uninstall bcrypt --save
bcrypt 지우는 것 잊지않기!
하지만 이번 프로젝트는 bcrypt로 계속 진행
2. 암호화 및 인증 function 만들기
bcrypt를 사용하는 방법은 다양하겠지만 여러 방식의 로그인 API에 적용하기 위해 함수를 따로 분리하겠다. bcrypt.js라는 파일을 생성하고 그 안에 암호화 및 인증 함수를 추가해준다.
bcrypt.js
const bcrypt = require('bcrypt');
const saltRounds = 5;
function Encrypt(pw) {
return new Promise((resolve, reject) => {
bcrypt.hash(pw, saltRounds)
.then((hash) => resolve(hash))
.catch((err) => console.log(err.message))
})
}
function Decrypt(inputPw, hash) {
return new Promise((resolve, reject) => {
bcrypt.compare(inputPw, hash, function (err, res) {
if (res == true) {
resolve()
} else {
reject({ msg: "비밀번호가 맞지 않습니다." })
}
})
})
}
exports.Encrypt = Encrypt;
exports.Decrypt = Decrypt;
Encrypt 함수에 Plaintext인 비밀번호를 넣고 돌리면 아래처럼 암호화된 형태로 비밀번호가 저장된다.
Bcrypt 해시 문자열의 형태
- $2a$ : bcrypt의 오리지날 버전은 $2$다. 오리지날 버전은 non-ASCII 문자나 널 문자를 처리하는 방법을 정의하지 않았다. $2a$는 널 문자를 포함하며, UTF-8로 인코딩 할 것을 정의한 버전이다. . 오리지날 버전은 non-ASCII 문자나 널 문자를 처리하는 방법을 정의하지 않았다. 널 문자를 포함하며, UTF-8로 인코딩 할 것을 정의한 버전이다. 위 DB에서 볼 수 있듯 게시하는 시점의 최신버전은 $2b$이다.
- 10$ : Cost의 크기는 2^10이다. Iteration count를 1024만큼 돌리겠다는 얘기다.
- N9qo8uLOickgx2ZMRZoMye : 랜덤하게 만든 salt
- ljZAgcFl7p92ldGxad68LJZdL17lhWy : 패스워드. Salt와 패스워드를 묶어서 해시해버렸기 때문에, 유추가 불가능하다.
솔팅
솔트(salt)는 단방향 해시 함수에서 다이제스트를 생성할 때 추가되는 바이트 단위의 임의의 문자열이다. 그리고 이 원본 메시지에 문자열을 추가하여 다이제스트를 생성하는 것을 솔팅(salting)이라 한다.
원래 비밀번호를 알아내더라고 솔팅된 digest를 대상으로 패스워드 일치 여부를 확인하기 어렵다.
일반적으로 모든 비밀번호가 랜덤한 고유의 솔트값을 가지고, 솔트값의 길이는 32 바이트 이상이어야 솔트와 digest를 추측하기 어렵다고 한다.
키 스트레칭
입력한 비밀번호의 digest를 생성하고, 생성된 digest를 입력 값으로 다시 digest를 계속 반복 생성하는 방법이다. 이 방법을 사용하면 공격자가 입력한 패스워드를 동일한 횟수만큼 해시해야만 digest의 일치 여부를 확인할 수 있다.
위에서 만든 bcrypt.hash함수에서 saltRounds의 값이 그 반복 횟수를 결정하게 된다.
bcrypt.js
const saltRounds = 5;
function Encrypt(pw) {
return new Promise((resolve, reject) => {
bcrypt.hash(pw, saltRounds)
.then((hash) => resolve(hash))
.catch((err) => console.log(err.message))
})
}
오류
간혹 모듈을 재설치하거나 실행할 때 아래 같은에러가 뜰 수 있음.
> bcrypt@5.0.1 install C:\Users\maru\Desktop\ws\CNT_Express_Store_JuJuClub\node_modules\bcrypt
> node-pre-gyp install --fallback-to-build
'node-pre-gyp'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는
배치 파일이 아닙니다.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! bcrypt@5.0.1 install: `node-pre-gyp install --fallback-to-build`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the bcrypt@5.0.1 install script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\maru\AppData\Roaming\npm-cache\_logs\2021-06-11T04_31_52_791Z-debug.log
bcrypt의 node-pre-gyp모듈에 대한 의존성과 관련된 오류로 설치부분에 추가설명한 bcryptjs 라이브러리를 활용하거나 node-pre-gyp모듈을 설치해줌으로써 해결할 수 있음.
npm i node-pre-gyp
참고
'BACK END > NODE.JS' 카테고리의 다른 글
replace함수로 string타입 데이터 가공 (0) | 2022.03.17 |
---|---|
cross-env (0) | 2022.03.17 |
REST 미지원 메서드 처리 (0) | 2022.03.17 |
Express 에서 Mongo DB 활용 로그 기록 기능 구현 (0) | 2022.03.17 |
Express-generator를 이용한 express 기본 구조 생성 (0) | 2022.03.17 |