Wecode -Foundation 2 (부트캠프)/인증, 인가- 개념

Foundation2- Node.js에서 Bcrypt, 해쉬함수 (makeHash, checkHash) **

Queen Julia 2023. 9. 18. 08:04

비밀번호 암호화 -> 고객 데이터 소중 

개인정보 보호 법령에 의거. 

백엔드 개발자라고해서 고객의 비밀번호를 알 수 없음 .

 

단방향. 돌아갈 수 없음. -> 해쉬 함수 

(한번 복호화 후에는 비밀번호를 볼 수 없음, 역함수 없음) 

(우리는 복호화 하는데, 이거를 풀려고 하는 사람이 있다. --> 해커들. 그렇기에 복잡하게 비밀번호 암호화 하는 것) 


1. 설치 

npm install bcrypt --save -dev

 

package.json에서 확인 

 

2. 쓸 수 있게 가져온다 

const bycrypt = require("bcrypt") ; 

 

 

3. 두개의 변수 선언

const bcrypt = require("bcrypt");

 

const password = 'password';      // 문자열 

const saltRounds = 12;   //솔팅 

  

const makeHash = async (password, saltRounds) => {  //인자에 문자열이 들어가야 하는데, password와 몇번 salting하는지

return await bcrypt.hash (password, saltRounds);

}                                     // 아까 다운 받은 bcrypt 모듈 안에, hash를 꺼내서, 이 hash의 password, saltRounds 를 전달한다. 

 

만약, 내부 개발자이라면, rainbow table로 

비밀번호를 알 수 있음

const bcrypt = require("bcrypt"); ---- (1)

const password = 'password'; ---- (2) 
const saltRounds = 12; ---- (3)

const makeHash = async (password, saltRounds) => {
  return await bcrypt.hash(password, saltRounds); ---- (4)
}

const main = async () => { 
  const hashedPassword = await makeHash(password, saltRounds); 
  console.log(hashedPassword);
}

main()
=> b'$2b$12$76taFAFPE9ydE0ZsuWkIZexWVjLBbTTHWc509/OLI5nM9d5r3fkRG'

b 붙어서 나올텐데 -> binary로 붙여서 해야 한다. 

 

'$2b라는 함수로 

$12번 해쉬 돌려서 

$뒤에 솔팅을 할거야'

원본 비밀번호 거꾸로 유추는 할 수 없지만 

솔트와 횟수도 알려주는데 , 대신 진짜 비밀번호 너 맞아? 

  • (1): bcrypt 모듈 import
  • (2): 암호화 할 평문
  • (3): Cost Factor
  • (4): hash() method로 암호화, 첫번째 인자로 암호화 하고 싶은 평문두번째 인자로 Cost Factor

 

뒤 문자열도 같아야 함. 

 

개발자를 위해, 그 문자열도 비교해주는 함수도 있음

 

 


솔팅(Salting)

단방향 해시 함수를 통해 암호화를 진행 할 때

본래 데이터에 추가적으로 랜덤한 데이터를 더하여 암호화를 진행하는 방식

원래 데이터에 추가 데이터가 포함 되었기 때문에 원래 데이터의 해시값과 다르게 됩니다.

 

--> 우연찮게 같은 패스워드를 쳐도 다르게 나오도록 

 

 

f(x) = 2x =y 이렇게 

어떤 함수인지, 몇번 돌렸는지, 어떤 그거인지 데이터베이스에 다 올라와서 알 수 있음. 숨기지 않음. 다 뚫어놓음 

데이터베이스 털려도 다 알 수. 

 

키 스트레칭(Key Stretching)

단방향 해쉬값을 계산 한 후, 그 해쉬값을 또 다시 해시하고 또 이를 반복하는 방식

최근에는 일반적인 장비로 1초에 50억 개 이상의 해시값을 비교할 수 있지만,

키 스트레칭을 적용하여 동일한 장비에서 1초에 5번 정도만 비교할 수 있습니다.

 

GPU(Graphics Processing Unit)를 사용하더라도 수백에서 수천 번 정도만 비교할 수 있습니다.

--> 솔트를 또 붙여서 여러 번 하는게 키 스트레칭 

 

라이브러리의 이름이 bcrypt  (자바스크립트 이외 언어에도 다 쓰는 라이브러리) 

 

 

단방향 암호화 vs 양방향 암호화 차이점 말해보라는 질문 -> 특징을 말하면 됨.

- 수업 듣고 추가할 것 (복잡한 함수를 쓴다 ) 

- 복호화 불가능 

- 솔팅 키스트레칭


<가입 흐름> 

client로부터 데이터 받고 

비밀번호 조건 체크 

비밀번호를 DB 저장 직전 

{비밀번호 암호화} -- salt , hashing 

 

<로그인 흐름>

client 데이터 가져오고

유저 유무 확인 -- 이메일로 

비밀번호 일치 여부 확인 

-- 이 시점에 사용 

 

 

요청을 보낼 때, 

백엔드 프론트 통신은 언제나 요청을 보낼 때니까 - http request의 headers에 담아


백엔드 서버는 

클라이언트와 데이터베이스 서버를 연결. 

 

[로그인]

데이터베이스에서 암호화된 비밀번호를 가져온 비밀번호 (select문) vs 외부 클라이언트가 보내준 req에 들어온 비밀번호 

= 일치하면 로그인 성공 -> 토큰 발급 

header에 convention인 Authorization 키에 토큰을 담아서 프론트에게 보내면, 

다시 우리는, "내가 보낸 토큰 맞아" 하고 토큰을 헤짚는.

 

[회원가입]

request가 담고 있는 유저가 전달해준 비밀번호와, getEncryptedPassword 함수로,

bcrypt의 makehash 함수를 써서,

유저가 전달한 비밀번호를, 

12번의 솔팅 거쳐서, hashing을 거쳐서 결과값을 어렵게 만든 다음, 

그 암호화된 것을 데이터베이스에 저장,

클라이언트가 준 비밀번호 (req.body)

 

백엔드는 늘 항상 중간에서. 
request받아오고, 데이터베이스에서 받아오고 비교하고. 

const password= 'password' 는 외부에서 받아오는 password

const hashedPassword = await makeHash (password, saltRounds);  는 데이터베이스에서 가져온 것

 

그래야 백엔드가 중간 개입자로서

왼쪽 (클라이언트 , 외부에서 들어온)  vs 오른쪽 (데이터베이스에서 긁어온) 

중간을 잡을 수 있으니. 

 

 

 

 

유저네임의 패스워드 (닉네임 or 이메일 불러와서 그의 패스워드를 데이터베이스에서 가져오는)

password를 가져오는데, 난수화된 패스워드일 테니 hashedPassword를 붙이는 것. 

 

토큰을 발행하면, payload안에 우리가 가지고 가야할 최소한의 유저 정보

userid, password 와 같은 정보를 담고 있을 것. 

http header의 특정 객체 안에, Authorization header에 토큰 있음.

Authorization을 까볼 수 있는 jwt 안의 verify함수 이용 

 

 


이상으로 bcrypt와 

bcrypt  안에 있는 해쉬함수, 

그 해쉬함수 모듈 안에 있는 makeHash, checkHash 에 대해 알아보았다.