본문 바로가기
엘리스 AI 트랙 4기/elice AI track

[6주차] crypto와 회원가입 구현하기

by _sweep 2022. 2. 23.

2월 23일 자 학습 내용 정리입니다.

 

 

✅ crypto

crypto는 Node.js의 기본 모듈로 OpenSSL의 해시, HMAC, 암호, 해독, 서명 및 확인 등의 암호화 기능을 제공한다.

회원가입 기능 구현 시 회원의 비밀번호를 그대로 데이터베이스에 저장하게 되면 관리자가 모든 회원의 비밀번호를 알 수 있고 탈취가 일어날 수 있어 보안 취약점이 발생한다.

따라서 이 경우 hash를 이용한다.

 

hash는 문자열을 되돌릴 수 없는 방식으로 암호화하는 방법이다.

해시 함수는 임의의 길이의 데이터를 고정된 길이의 데이터로 매핑하는데 이 결과로 얻어진 해시 값은 원래의 형태로 되돌릴 수 없다.

 

출처 : https://ko.wikipedia.org/wiki/%ED%95%B4%EC%8B%9C_%ED%95%A8%EC%88%98

 

회원가입 구현 시 hash를 이용하는 방법은 다음과 같다.

  1. 입력받은 비밀번호의 hash 값을 데이터베이스에 저장한다.
  2. 이후 로그인 시 입력받은 비밀번호의 hash 값을 구하고 데이터베이스에 저장된 비밀번호의 hash 값과 비교한다.

 

let crypto;
try {
  crypto = await import('crypto');
} catch (err) {
  console.log('crypto support is disabled!');
}

const hash = crypto.createHash('sha1');
hash.update(password);
hash.digest('hex');

 

crypto에서는 간단하게 sha1 알고리즘을 사용하거나 보다 강력한 sha224, sha256 등의 알고리즘을 사용할 수 있다.

 

 

✏️ 예제 - 회원가입 구현하기

회원가입을 구현하는 방식은 다음과 같다.

  • 회원가입 페이지 구현
  • 이메일 형식, 비밀번호 확인 문자 확인
  • post 요청 전송
  • 회원가입 처리 및 redirect

 

✔️ 회원가입 페이지 구현

...
form(action="/join" method="post" onsubmit="return check()")
  table
    tbody
      tr
        td 이메일
        td: input(type="text" name="email")
      tr
        td 이름
        td: input(type="name" name="name")
      tr
        td 비밀번호
        td: input(type="password" name="password")
      tr
        td 비밀번호 확인
        td: input(type="password" name="password_confirm")
     tr
        td(colspan="2")
          input(type="submit" value="가입하기")
...

 

회원가입 페이지를 구현한 코드이다.

POST 요청을 보내기 위해 form을 사용했고 입력받을 이메일, 이름, 비밀번호, 비밀번호 확인 칸을 생성했다.

 

✔️ 유효 값 체크

...
script.
  function check() {
    const email = document.querySelector('[name="email"]').value;
    if (!/^\S+@\S+\.\S+$/.test(email)) {
        alert('이메일 형식이 올바르지 않습니다.');
        return false;
    }
  
    const password = document.querySelector('[name="password"]').value;
    if (password.length < 8) {
        alert("최소 8자리 이상의 비밀번호를 설정해 주세요.");
        return false;
    }
  
    const passwordConfirm = document.querySelector('[name="password_confirm"]').value;
    if (password != passwordConfirm) {
        alert('비밀번호 확인이 일치하지 않습니다.');
        return true;
    }
    return false;
}

 

이후 script에서 입력받은 값들이 유효한 값인지 확인한다.

email은 xxx@xxxx.xxxx의 값인지, password는 8 이상의 길이를 가지고 있는지, passwordConfirm이 입력한 비밀번호와 일치하는지 판별한다.

form을 새로고침 하지 않기 위해 모두 유효한 값을 가질 경우 false를 리턴한다.

 

✔️ 회원가입 요청 처리

...
router.post(url, async(req, res) => {
    const { email, name, password } = req.body;
    const pwHash = getHash(password);
    
    const exists = await User.findOne({ email });
    if (exists) {
        throw new Error('이미 가입된 메일입니다');
    }
    
    await User.create({
        email,
        name,
        password: pwHash,
    });
    
    res.redirect('/');
});
...

 

POST 요청이 들어오면 입력으로 들어온 email, name, password를 받아온다.

그리고 password는 암호화시킨다.

 

id로 사용될 이메일은 유일해야 하기 때문에 이미 회원가입을 한 이메일인지 확인한 후 존재하는 이메일일 경우 에러를 반환한다.

email이 존재하지 않는 경우 정상적으로 회원가입 절차를 진행하며 User에 email, name, password를 저장한다.

이때 password는 암호화된 값으로 저장한다.

 

이 과정까지 모두 끝났다면 회원가입이 끝났다는 의미로 사용자를 메인 화면으로 redirect 시킨다.

 

 

🔍 참조

crypto https://nodejs.org/api/crypto.html#determining-if-crypto-support-is-unavailable

해시 함수 https://ko.wikipedia.org/wiki/%ED%95%B4%EC%8B%9C_%ED%95%A8%EC%88%98

 

댓글