기술 면접 준비는 떨면뭐하니~!

김민섭·2022년 12월 16일
0

실전 프로젝트

목록 보기
3/3
post-thumbnail

프로젝트의 시작

저를 포함한 개발자로써 취직을 도전하시는 분들이라면 면접, 특히 기술 면접에 대한 두려움이 있을거라고 생각했습니다.
그래서 개발자 취직을 준비하는 분들에게 모의 면접을 제공해주면 어떨까? 하는 생각에서 이 프로젝트를 시작하게 되었습니다.

떨면 뭐하니 프로젝트는 자신이 사용하는 기술에 대한 질문을 음성 및 텍스트로 제공, 면접 화면을 녹화하여 자신의 표정, 억양, 말의 빠르기 등의 요소와 질문별 답변 시간을 제공해 실제 면접에서 자신의 기술 스택에 대한 질문들을 대비할 수 있게 하였습니다.

프로젝트에서 맡은 역활

이번 프로젝트에서 맡은 역활은 로그인, 토큰 발급, 인증 미들웨어, 개인정보 수정, 휴면회원 관리, CI/CD, 개인회원 테스트 코드 작성을 맡게 되었다.

내가 프로젝트에서 고민했던 것들

  1. CI/CD를 어떻게 구현할 것인지

  2. 테스트 코드의 중요성을 팀원들에게 어떻게 어필할 것인지

  3. 함수 및 전체적인 코드를 어떻게 구성할 것인지

  4. 로그인 시 비밀번호를 어떤 방식으로 암호화 할 것인지

  5. 토큰을 발급하는 코드의 구성을 어떻게 할 것인지

  6. 토큰에 어떠한 정보를 담아줄 것인지

  7. 토큰이 탈취되었을 때를 어떻게 대비할 것인지

CI/CD

백엔드는 부리더를 맡은 구성원의 서버를 이용하고 있었다.
서버에 수정사항을 반영할 일이 생기면 다들 부리더를 찾아가야 하는 상황이었고 이러한 상황들은 다음과 같은 문제들을 발생시켰다.

  • 문제 상황
  1. 팀원들의 집중하는 시간대가 각자 달라서 밤늦게 까지 작업하는 팀원이 있으면 부리더가 새벽 늦게까지 남아있어야 했다.

  2. 부리더가 팀원들의 코드를 반영하기 바빠 자신의 코드 작성에 집중하지 못하는 상황이 생겼다.

이러한 문제들을 해결하기 위하여 CI/CD의 도입 필요를 느끼게 되었다.

그리하여 팀원들에게 부리더의 부담을 줄일 수 있다는 것과 팀의 생산성을 높일 수 있다는 점을 어필한 결과 도입해 보면 좋겠다는 의견을 받아낼 수 있었다.

  • 생각했던 방법들
  1. Jenkins
  2. AWS codeDeploy
  3. Github Actions

1안의 경우 Jenkins를 위한 인스턴스가 필요하고, 셋팅이 복잡했다.
2안의 경우 AWS 하나로 관리가 가능하지만 요금이 발생하는 단점이 있었다.
3안의 경우 별도의 툴이 필요하지 않았고 별도의 요금없이 Github에서 관리할 수 있었다.

코드적용이 빈번하게 발생하는 프로젝트의 막바지 때 CI/CD를 적용하게 되었기 때문에 간단하게 구현할 수 있으며 별도의 요금이 발생하지 않는 Github Actions를 선택하게 되었다.

테스트 코드

테스트 코드의 중요성은 익히 알고 있던 바였다. 테스트 코드를 사용함으로써 얻는 이익은 다음과 같다고 생각한다.

  1. 코드상에서 불필요한 부분은 빠지게 되고 정말 필요한 부분만 남게된다.
  2. 개발자가 정말 필요한 부분들에만 집중할 수 있게 도와준다.
  3. 다른 개발자가 테스트 코드를 작동시켜 보며 해당 코드를 이해하는데 도움을 줄 수 있다.
  4. 자신이 작성한 코드의 신뢰성을 손쉽게 확인할 수 있다.
  5. CI/CD를 구축 했을 때 잘못된 코드가 올라가지 않도록 해준다.

이러한 이유들로 인해서 테스트 코드의 도입을 초반에 어필해 보았으나 두가지의 문제로 인해 받아들여지지 않았다.

  1. 테스트 코드를 작성해야 하는 이유에 대해서 충분하게 납득을 시키지 못했다.
  2. 테스트 코드를 작성해 본 경험이 있는 사람이 나 외에는 없었다.

그러다 프로젝트의 막바지가 되어서 테스트 코드를 작성해보자는 의견이 받아들여졌다. 아마도 대부분의 기능 구현이 끝난 상태여서 다들 마음의 여유가 생긴것이 크다고 생각한다.

프로젝트의 막바지에 적용해야 했기 때문에 여러가지 라이브러리를 찾아볼 수 있는 시간적 여유가 부족했고, 그 결과 내가 유일하게 알고 있는 Jest를 이용해 테스트 코드를 작성, 코드의 전반적인 흐름을 테스트 해볼 수 있는 통합테스트만 작성하게 되었다.

로그인과 토큰발급

이 부분이 내가 가장 생각을 많이 하게 된 부분이다.

내가 중점적으로 생각했던 부분은 다음과 같다.

  1. 로그인 시 비밀번호를 어떻게 암호화 할 것인지
  2. 토큰이 탈취되었을 때를 어떻게 대비할 것인지
  3. 토큰에 어떠한 정보를 담아줄 것인지
  4. 토큰을 발급하는 코드의 구성을 어떻게 할 것인지

로그인 시 암호화를 해야 하는 이유

우선 비밀번호를 입력받은 그대로 DB에 저장하는 것은 범죄나 다름 없다고 생각한다.
DB가 해킹당하는 순간, 고객들의 비밀번호를 고스란히 해커에게 넘겨주기 때문이다.
해커들은 탈취한 아이디와 비밀번호로 여러 사이트에 대입해 볼 것이며 다른 보안이 좋은 사이트까지 뚫릴 수 있다. 그러므로 비밀번호는 반드시 암호화하여 저장해야 한다.

로그인 시 암호화 방법으로는 암호화의 대표적인 방법인 Crypto와 Bcrypt를 생각하고 있었다.

비밀번호 암호화로 bcrypt를 사용한 이유

암호화 하는 방법으로 crypto와 bcrypt를 고려해 보았는데 blowfish를 사용하는 bcrypt의 강력한 해시 기능이 마음에 들었다.

아래의 두가지 관점으로 보았을 때 bcrypt가 가장 가성비가 좋다는 글을 참고하기도 했다.

보안성: 결국 공격자가 내가 암호화한 값을 알아내는데 걸리는 시간을 최대한 늦춰야 하는 궁극적인 목적을 얼마나 달성할 수 있는가?

경제성: 보안성을 챙기기 위해 내가 포기해야 하는 경제적 비용(CPU 연산 속도나 메모리 오버헤드 등)

출처: https://velog.io/@shin0805/%EC%99%9C-bcrypt

공격자는 컴퓨터자원을 무제한으로 보유하지 않기 때문에, 공격자의 속도를 늦출 수록 암호화 해독이 어려워질 것이다.

즉, 어느정도의 경제성을 포기하더라도 사용자들의 보안을 강화하는 bcrypt를 사용하는 것이 옳다는 판단을 내리게 되었다.

토큰이 탈취되었을 때를 어떻게 대비할 것인지

우선 유저인증 수단으로 JWT를 사용하였다. 별도의 서버비용이 들지 않고, 확장성까지 좋은 인증수단이기 때문이다.

처음에 고민했던 부분은 토큰이 탈취되었을 때의 문제점이었다. 토큰이 탈취가 된다면 남아있는 유효기간동안 해커를 막을 방법이 없기 때문이다.

즉, 유효기간을 늘리면 보안에 취약해지고, 유효기간을 줄이면 사용자가 그만큼 자주 로그인을 해야 하는 불편함이 생기는 문제가 있다.

이것을 해결하기 위해서 RefreshToken을 적용하게 되었다. AccessToken과 RefreshToken 두 개의 토큰을 사용하여 위의 문제점을 어느정도 해결했다고 생각하였는데 문득 RefreshToken이 탈취당하면 어떻게 하지...? 라는 의문이 들었다.

이것을 해결하려고 노력한 방법은 아래에 주소에 정리해 놓았다.

주소: https://velog.io/@keeper1826/token-%EA%B0%92-%ED%83%88%EC%B7%A8-%ED%94%BC%ED%95%B4%EB%A5%BC-%EC%B5%9C%EC%86%8C%ED%99%94-%ED%95%B4%EB%B3%B4%EC%9E%90

토큰에 어떠한 정보를 담아줄 것인지

이 생각은 금방 답을 내릴 수 있었다. 토큰에 아주 최소한의 정보만 담은 후 인증 미들웨어를 거칠 때마다 DB에 접근하여 유저의 정보를 찾아 오는 방법을 선택했다. 토큰의 Payload는 암호화가 되지 않는다는 사실을 인지하고 있었기 때문에 서버에서 조금의 손실을 보더라도 최소한의 정보만을 토큰에 담는것이 옳다고 생각한 까닭이다.

토큰을 발급하는 코드의 구성을 어떻게 할 것인지

우선 Sign과 Verify 함수를 jwt-util 파일에서 관리하였다. 함수를 따로 util에서 정리해 놓은 후 로그인 시 가져다 쓰는 방법을 택한 것이다. 이러한 방법을 택한 이유는 향후 코드의 수정이 필요할 때 손쉽게 수정을 할 수 있다고 생각하였고, 무엇보다 로그인 시 토큰을 발급하는 서비스 부분의 코드를 깔끔하게 유지하고 싶었던 이유가 컸다

jwt-util 코드

로그인 서비스 로직 코드

휴면회원 관리

이번 프로젝트에서는 한달동안 로그인을 하지 않은 유저는 휴면회원 처리를 하여 이메일 인증을 해야만 사이트를 이용할 수 있게 하였다.

주기적으로 정해진 시간에 로직을 실행시킬 수 있는 라이브러리를 찾아보다가 Node-schedule을 찾게 되어 적용하였다.

내가 생각한 방법
1. DB에 LoginHistory (마지막으로 로그인한 기록), expiration (휴면상태인지 아닌지를 표현) 이렇게 두 가지의 column을 만든다.
2. 로그인을 할 때마다 그 계정의 LoginHistory를 현재 날짜와 시간으로 업데이트 한다.
3. 매일 00시 00분 마다 DB에 저장된 모든 유저들의 LoginHistory에 1달을 더한다.
4. 1달을 더한 값이 현재의 시간보다 과거라면 expiration을 true로 바꿔서 휴면계정으로 만든다.

구현 과정

1번과 2번은 mongoose를 이용한 findOneAndUpdate를 사용하여 평소에 하던 것처럼 손쉽게 할 수 있었기 때문에 생략했다.

3번 같은 경우는 nodeschedule을 이용했다.
nodeschedule의 시간을 매일 00시 00분으로 맞춰놓고 유저 DB에서 마지막 로그인 기록을 가져온 뒤 setMonth를 사용해서 한달을 더해 주었다.

더하는 과정에서 한달을 더해주는 기능은 함수로 따로 만들어서 관리를 해주었다.

profile
getting ready to run

0개의 댓글