본문 바로가기

[Express + Node]

[Node] bcrypt로 비밀번호 암호화하는 방법 (React 연동)

728x90

[Express] GET 메서드를 사용한 API 개발

 

[Express] GET 메서드를 사용한 API 개발

[Express] 백엔드 개발 기본 설정 [Express] 백엔드 개발 기본 설정🚩소개안녕하세요! 대학생 개발자 주이어입니다. 오늘은 Node와 Express를 사용하여 서버를 개발할 때 필요한 라이브러리 다운 및 기

juyear-coding.tistory.com

추천 글 보러가기

🚩소개

안녕하세요! 대학생 개발자 주이어입니다! 이번 글에서는 사용자의 비밀번호를 bcrypt로 해시화 및 암호화를 통해 보안을 강화하는 법에 대해서 알아보려고 합니다. 사용자의 정보를 다루는 웹 서비스를 만들 때, 비밀번호를 평문으로 저장하는 건 정말 위험합니다.

그래서 실제 서비스에서는 bcrypt와 같은 보안 알고리즘을 통해 비밀번호를 암호화해서 저장합니다.

 

추가로 React에서 진행하고 있는 프로젝트이기 때문에, React와 연동해서 사용하는 부분까지 보여드리도록 하겠습니다.


ℹ️bcrypt에 대해서

먼저 bcrypt는 비밀번호와 같은 민감한 데이터를 해싱(hash)하기 위해 널리 사용되는 라이브러리입니다. 단순한 암호화 방식과는 달리, 해싱은 되돌릴 수 없는(복호화가 불가능한) 일방향 암호화 방식으로, 같은 입력값이라도 항상 같은 결과가 나오지 않도록 설계되어 있어 보안에 강력합니다.

 

bcrypt를 사용하는 이유는 아래와 같습니다.

  • 안정성 : bcrypt는 내부적으로 salt를 자동으로 생성해 해시값에 추가함으로써, 같은 비밀번호라도 다른 해시값을 생성합니다.
  • 비교 기능 제공 : 사용자가 입력한 비밀번호와 해시된 비밀번호를 비교하는 기능을 쉽게 사용할 수 있습니다.
  • node.js 호환 : bcrypt는 node.js 환경에서 매우 쉽게 사용할 수 있고(라이브러리 설치만으로) 많은 프로젝트에 자주 사용됩니다.

이런 이유로 저도 프로젝트에 bcrypt 암호화를 사용하기로 했습니다.


💻bcrypt 사용

라이브러리 설치

bcrypt를 완벽히 이해하고 직접 구현해서 사용하는 것은 굉장히 어렵습니다. 하지만 node.js에서는 bcrypt를 쉽게 사용할 수 있도록 라이브러리를 제공하기 때문에 자유롭게 사용할 수 있습니다.

npm install bcryptjs

먼저 라이브러리를 사용하기 위해 bcryptjs 라이브러리를 다운받아 줍니다.

참고로 bcrypt라는 라이브러리도 있지만, bcrypt는 배포 시 Windows나 Node버전에 따라 오류가 날 수 있기 때문에 bcryptjs를 사용해 주었습니다.(실제로 bcrypt 사용해서 배포하다가 오류나서 바꿈..)

기능은 완전히 똑같지만, bcryptjs가 성능이 살짝 떨어진다는 단점이 있습니다.

비밀번호 암호화하기

import bcrypt from "bcryptjs";

app.post("/account", async (req, res) => {
  const { email, userId, password } = req.body;
  const user = await getUserDB(userId);
  const existEmail = await getEmailDB(email);
  const query =
    "INSERT INTO user_info (userId, email, password) VALUES (?,?,?)";

  if (user) {
    res.json({ success: false, message: "이미 존재하는 아이디 입니다." });
  } else if (existEmail) {
    res.json({ success: false, message: "이미 존재하는 이메일 입니다." });
  } else {
    try {
      const saltRounds = 10;
      const hashedPassword = await bcrypt.hash(password, saltRounds);
      const [result] = await db.execute(query, [userId, email, hashedPassword]);
      res.json({ success: true, message: "가입이 완료되었습니다." });
    } catch (err) {
      console.error(err);
    }
  }
});

위 코드는 제가 프로젝트에서 사용하고 있는 account 백엔드 API 입니다.

간단하게 클라이언트에서 제공받은 데이터를 이용해 user_info 테이블에 데이터를 추가하는 코드입니다.

 

여기서 봐야할 부분은 try문 사이에 있는 코드입니다.

const saltRounds = 10;


먼저 saltRounds 상수를 만들어 10을 넣어주었습니다. 여기서 salt값은 해시의 복잡도를 의미하고, 10이라는 것은 2의 10승인 1024번을 반복하여 해시 값을 생성하겠다는 의미입니다.

const hashedPassword = await bcrypt.hash(password, saltRounds);

 

salt값을 설정해줬으니 이제 해시화를 할 차례입니다. 해시화를 하기위해서는 bcryptjs에서 제공하는 hash기능을 사용하면 됩니다.
bcrypt.hash(암호활 데이터, salt값) 형식으로 사용해주시면 됩니다.

bcrypt 해시화

저장된 데이터를 확인해보면 위와 같이 암호화가 잘 되어서 저장되는 것을 알 수 있습니다.

암호화된 비밀번호 비교하기

이제 비밀번호가 암호화돼서 저장되었으니 로그인할 때 비교만 해주면 됩니다.
비교를 해주기 위해서는 로그인 시 사용자가 입력한 비밀번호를 가져와 비교해주면 되는데, 또 해시화 할 필요 없이 bcryptjs에서 지원해주는 compare 기능을 사용하면 바로 비교가 가능합니다.

app.post("/login", async (req, res) => {
  const { userId, password } = req.body;
  const user = await getUserDB(userId);

  if (!user) {
    res.json({ success: false });
  } else {
    try {
      const isMatch = await bcrypt.compare(password, user.password);
      if (isMatch) {
        return res.json({ success: true });
      } else {
        res.json({ success: false });
      }
    } catch (err) {
      console.error(err);
      res.json({ success: false });
    }
  }
});

위 코드는 제가 프로젝트에서 사용 중인 login API 입니다. 

const isMatch = await bcrypt.compare(password, user.password);

compare 기능을 사용하여 비밀번호가 같은지를 비교하는 코드입니다.

bcrypt.compare(비교할 데이터, 암호화된 데이터) 이런 식으로 사용하시면 됩니다.

 

await를 사용해주셔야 하고(비교하여 값을 받아오는 것을 기다려줘야 하기 때문에) 결과는 boolean 형식이며, true나 false 저장됩니다.

if (isMatch) {
    return res.json({ success: true });
} else {
    res.json({ success: false });
}

isMatch가 true면 비교한 값이 같다는 뜻이기 때문에, 로그인 성공으로 판단해주었고, false일 경우 비교한 값이 다르다는 뜻이기 때문에 실패로 판단해주었습니다.

React 연동

if (inputData.password === inputData.confirmPW) {
  axios
    .post("https://woostar.fly.dev/account", {
      email: inputData.email,
      userId: inputData.userId,
      password: inputData.password,
    })

React에서 따로 해줄 설정은 없고, 평소 하던대로 백엔드 API를 요청하시면 됩니다.

비밀번호 입력

위와 같이 클라이언트에서 비밀번호를 입력하고 로그인을 하면 백엔드에서 bcrypt 값과 비교해 성공 여부를 판단하게 됩니다.


😊마치면서...

오늘은 이렇게 bcrypt를 사용하여 비밀번호나 민감한 데이터를 암호화 하는 방법에 대해서 정리해보았습니다.
소규모 프로젝트나, 개인 프로젝트라면 큰 문제가 없을 수 있지만 보안은 항상 중요하니 적용해보았습니다.

bcrypt뿐만 아니라 다양한 암호화 방법이 존재하니 다음에는 다른 방법도 사용해보고 정리해볼 생각입니다.

 

지금까지 읽어주셔서 감사합니다! 다음 글은 더 도움되는 정보로 가져오겠습니다!

 

[React] 실시간 검색 - debouncing 기능 구현하기

 

[React] 실시간 검색 - debouncing 기능 구현하기

[React, Express] 서버 구현 및 데이터베이스 연결하기(REST API) [React, Express] 서버 구현 및 데이터베이스 연결하기(REST API)[EZ_Scheduler] - [React] 로그인 페이지 스타일링 [React] 로그인 페이지 스타일링📌

juyear-coding.tistory.com

React 추천글 읽으러 가기

728x90