Project/codestates-final-project

리펙토링 및 개선 - 3 / Bcrypt 적용

fullfish 2022. 5. 31. 01:57

Bcrypt에 대해 내가 쓴 글

https://fullfish.tistory.com/123?category=1054038 

 

Hash와 Salt 그리고 Bcrypt

기본 용어 hash : 다양한 길이를 가진 데이터를 고정된 길이의 데이터로 매핑하는것 digest : hash에 의해 암호화된 데이터 avalanche(눈사태) 효과 : 작은 변화에도 결과가 완전히 달라짐 rainbow 공격 :

fullfish.tistory.com

주요 개념을 위에 정리해뒀으며

 

서버단에서 적용은

// signUp
bcrypt.genSalt(13, async function (err, salt) {
    bcrypt.hash(password, salt, async function (err, hash) {
      userInfo.password = hash;
      const result = await userInfo.save();
      await slack.slack("User Post 201", `id : ${result.dataValues.id}`);
      return res.status(201).send({ data: { id: result.dataValues.id } });
    });
  });

 

// signIn 전문
in: {
  post: async (req, res) => {
    try {
      const { email, password } = req.body;
      if (!email || !password) {
        await slack.slack("Signin Post 422");
        return res.status(422).send({ message: "insufficient parameters supplied" });
      }
      const userInfo = await user.findOne({
        where: {
          email,
        },
      });
      //데이터베이스에 email이 없을때
      if (!userInfo) {
        await slack.slack("Signin Post 400");
        return res.status(400).send({ message: "Wrong email" });
      } else {
        bcrypt.compare(password, userInfo.password, async function (err, result) {
          //데이터베이스에 email 있지만 비밀번호가 틀릴때
          if (result === false) {
            await slack.slack("Signin Post 400");
            return res.status(400).send({ message: "Wrong password" });
          }

          //데이터 베이스에 회원정보가 있을 경우
          else {
            const payload = {
              id: userInfo.id,
              email,
            };
            const accessToken = jwt.sign(payload, process.env.ACCESS_SECRET, {
              expiresIn: "30m",
            });
            const refreshToken = jwt.sign(payload, process.env.REFRESH_SECRET, {
              expiresIn: "6h",
            });
            res.cookie("refreshToken", refreshToken, {
              sameSite: "Strict",
              httpOnly: true,
              secure: false, // https로 바꾼후에 true로 바꿔야함
            });
            await slack.slack("Signin Post 200", `id : ${userInfo.id}`);
            res.status(200).send({
              data: { id: userInfo.id },
              accessToken: accessToken,
            });
          }
        });
      }
    } catch (err) {
      await slack.slack("Signin Post 501");
      res.status(501).send("Signin Post");
    }
  },
},

흐름은 예를들어

클라이언트에서 password가 '1234'로 회원가입을 할시에

서버로 '1234'가 온다

hashing을 하여 digest를 얻는다

digest를 db에 저장한다

클라이언트에서 password가 '1234'로 로그인을 할시에

서버로 '1234'가 온다

검증함수에 '1234'와 db에 저장된 digest를 넣는다

digest에 있는 salt를 참조해 '1234'를 hashing한다

얻어진 digest가 db에 있는 digest와 같으면 검증이 되었다

이런식으로 했다