본문 바로가기

과거공부모음

나의 개발일지 TIL(Today I learned) - 미들웨어, nodemon, JWT, mongoose exec(), cookie, sesstion

Today I learned

오늘은 node.js 심화 과정을 학습하면서 todo-list를 위한 서버를 만들면서 학습을 진행했다
진행을 하면서 설명이 부족하다고 느끼는 부분과 잘 이해가 안가는 부분을 더 찾아보면서 학습을 진행했다

  • 미들웨이
  • nodemon
  • mongoose exec()
  • cookie, session
  • JWT
  • Stateless, Statful

미들웨어

미들웨어는 요청과 응답의 중간에 위치해서 미들웨어라고 불리고 요청과 응답을 조작하여 기능을 추가하기도 하고, 나쁜 요청을 걸러내기도 한다

express는 자체적인 최소한의 기능을 갖춘 라이팅 및 미들웨어 웹 프레임워크 express 애플리케이션은 기본적으로 일련의 미들웨어 함수 호출이다

express 내에서 웹 요청과 응답에 대한 정보를 사용해서 필요한 처리를 진행 할 수 있도록 분리된 독립적인 함수 그리고 각각 미들웨는 next() 메서드를 호출해서 그 다음 미들웨어가 작업을 처리할 수 있도록 순서를 넘길 수 있다

app.get('/set-session', function (req, res, next) {
  const name = 'sparta';
  const uniqueInt = Date.now();
  session[uniqueInt] = { name };

  res.cookie('sessionKey', uniqueInt);
  return res.status(200).end();
});

코드에서 function(req, res, next) {} 부분이 미들웨이 이다

nodemon

프로젝트의 파일들을 모니터링하다가 수정되는 경우 자동으로 서버를 재실행 시켜주는 스크립트 모니터링 유틸리티이다

설치

npm install -D nodemon

개발할때 사용하는 패키지라서 -D옵션을 사용해 “devDependencies”에 추가한다 package.json의 스크립트 부분에 "dev": "nodemon app”를 추가하면 npm run dev를 콘솔창에 입력하면 사용이 가능하다

mongoose exce()

find, findOne, findById, findOneAndUpdate 등의 메서드의 리턴값은 Query이다 Mongoose Query는 프로미스가 아니고 then을 사용할 수 있는 일종의 유사 프로미스 이다

find, findOne등의 메서드 뒤에 exec()를 붙이든 안붙이든 기능은 동일하다 대신 exec()를 사용하면 유사 프로미스가 아닌 온전한 프로미스를 반환값으로 얻을 수 있다 에러가 났을 때 오류가 발생한 코드의 위치가 포함되기 때문에 공식 문서에서 exec()를 사용하는 것을 권장한다

cookie, sesstion

쿠키와 세션의 차이점은 크게 상태 정보의 저장 위치 쿠키는 클라이언트(로컬 PC)에 저장하고 세션은 서버에 저장한다

클라이언트와 서버가 통신을 할 때 통신이 연속적이지 않고 한 번 통신이 되면 끊어진다 따라서 서버는 클라이언트가 누구인지 계속 인증을 해줘야 한다 하지만 너무 번거롭다 이런 문제를 해결하는 방법이 쿠키와 세션이다

쿠키 (Cookie)

HTTP의 일종으로 사용자가 어떠한 웹 사이트를 방문할 경우 그 사이트가 사용하고 있는 서버에서 사용자의 컴퓨터에 저장하는 작은 기록 정보 파일 HTTP에서 클라이언트의 상태 정보를 클라이언트의 PC에 저장하였다가 필요시 정보를 참조하거나 재사용 할 수 있다

  • 쿠키 특징
    • 이름, 값, 만료일(저장기간), 경로 정보로 구성
    • 클라이언트에 총 300개의 쿠키를 저장할 수 있다
    • 하나의 도메인 당 20개의 쿠키를 가질 수 있다
    • 하나의 쿠키는 4KB(=4096byte)까지 저장 가능
  • 쿠키의 동작 순서
    • 클라이언트가 페이즈를 요청한다(사용자가 웹사이트에 접근
    • 웹 서버는 쿠키를 생성
    • 생성한 쿠키는 클라이언트가 가지고 있다가(로컬 PC에 저장) 다시 서버에 요청할 때 요청과 함께 쿠키를 전송
    • 동일 사이트 재방문 시 클라이언트의 PC에 해당 쿠키가 있는 경우, 요청 페이지와 함께 쿠키를 전송한다
  • 사용 예시
    • 방문 사이트에서 로그인 시, 아이디와 비밀번호를 저장하시겠습니까?
    • 팝업창을 통해 오늘 이 창을 다시 보지 않기 체크

세션 (Session)

일정 시간 동안 같은 사용자로 들어오는 요구를 하나의 상태로 보고 그 상태를 유지시키는 기술 여기서 일정 시간은 방문자가 웹 브라우저를 통해 웹 서버에 접속한 시점부터 웹 브라우저를 종료하여 연결을 끝내는 시점을 말한다 방문자가 웹 서버에 접속해 있는 상태를 하나의 단위로 보고 그것을 세션이라고 한다

  • 세션 특징
    • 웹 서버에 웹 컨테이너의 상태를 유지하기 위한 정보를 저장
    • 웹 서버의 저장되는 쿠키
    • 부라우저를 닫거나, 서버에서 세션을 삭제했을 때 삭제가 되어서 쿠키보다 비교적 보안이 좋다
    • 저장 데이터에 제한이 없다 (서버 용량이 허용하는 선)
    • 각 클라이언트에 고유 Session ID를 부여 Session ID로 클라이언트를 구분해 각 요구에 맞는 서비스를 제공
  • 세션의 동작 순서
    • 클라이언트가 페이지에 요청한다 (사용자가 웹사이트 접근)
    • 서버는 접근한 클라인트의 Request-Header필드인 Cookie를 확인해 클라이언트가 해당 session-id를
      보냈는지 확인
    • session-id가 존재하지 않는다면 서버는 session-id를 생성해 클라이언트에게 돌려준다
    • 서버에서 클라이언트로 돌려준 session-id를 쿠키를 사용해 서버에 저장한다
    • 클라이언트는 재접속 시, 이 쿠키를 이용해 session-id 값을 서버에 전달한다
  • 사용 예시
    • 화면을 이동해도 로그인이 풀리지 않고 로그아웃하기 전까지 유지

JWT

Token 인증 시스템이다 Token 인증 시스템은 클라이언트가 서버에 접속을 하면 서버에서 해당 클라이언트에게 인증되었다는 의미로 토큰을 부여한다 부여 받은 토큰은 유일하다 토큰을 발급받은 클라이언트는 다시 서버에 요청을 보낼 때 요청한 헤더에 토큰을 심어서 보낸다 그러면 서버에서는 클라이언트로 받은 토큰을 서버에서 제공한 토큰과 일치하는지 체크를 하는 인증 과정을 처리한다

  • 토큰 동작 순서
    • 클라이언트가 아이디와 비밀번호로 로그인 한다
    • 서버 측에서 클라이언트에게 토큰을 발급한다(유일한 토큰)
    • 클라이언트는 서버 측에서 전달받은 토큰을 쿠키나 스토리지에 저장해 두고, 서버에 요청을 할 때 해당 토큰을 HTTP요청 헤더에 심어서 보낸다
    • 서버는 전달받은 토큰을 검증하고 요청에 응답한다 토큰에 요청한 클라이언트의 정보가 담겨있기에 서버는 DB를 조회하지 않고 누가 요청 했는지 알 수 있다
  • 토큰 방식의 단점
    • 쿠키/세션과 다르게 토큰 자체의 데이터 길이가 길어, 인증 요청이 많아질수록 네트워크 부하가 심해질 수 있다
    • Payload 자체는 암호화되지 않기 때문에 유저의 중요한 정보는 담을 수 없다
    • 토큰을 탈취당하면 대처하기 어렵다 (따라서 사용 기간 제한을 설정하는 식으로 극복한다)
  • JWT(JSON Web Token)
    • JWT란 인증에 필요한 정보들을 암호화시킨 JSON토큰 의미하다 그리고 JWT기반 인증은 JWT토큰(Access Token)을 HTTP헤더에 실어 서버가 클라이언트를 식별하는 방식이다
    • JWT는 JSON데이터 Base64 URL-safe-Encode를 통해 인코딩하여 직렬화한 것이다 토큰 내부 에는 위변조 방지를 위한 개인키를 통한 전자서명도 들어있다 따라서 사용자가 JWT를 서버로 전송하면 서버는 서명을 검증하는 과정을 거치고 검증이 완료되면 요청한 응답을 돌려준다

JWT 구조

JWT는 .을 구분자로 나누어지는 세 가지 문자열의 조합이다 .을 기준으로 좌측부터 Header, Payload, Signature
의미한다

Header에는 JWT에서 사용할 타입과 해시 알고리즘의 종류가 담겨있다 Payload는 서버에서 첨부한 사용자 권한 정보와 데이터가 담겨있다 Signature에는 Header, Payload를 Base64 URL-safe Encode를 한 이후 Header에 명시된 해시 함수를 적용하고, 개인키(Private key)로 서명한 정자 서명이 담겨있다 전자서명에는 비대칭 암호화 알고리즘을 사용하므로 암호화를 위한 키와 복호화를 위한 키가 다르다 암호화에는 개인키 복호화에는 공개키를 사용한다

 

Header : alg : 서명 암호화 알고리즘, typ : 토큰 유형

Payload : 서버와 클라이언트가 주고받는 시스템에서 실제로 사용될 정보에 대한 내용 페이로드는 정해진 데이터 타입은 없지만, 대표적으로 Registered claims, Public claims, Private claims 이렇게 세 가지로 나뉜다.

  • Registed claims : 미리 정의된 클레임.
    • iss(issuer; 발행자),
    • exp(expireation time; 만료 시간),
    • sub(subject; 제목),
    • iat(issued At; 발행 시간),
    • jti(JWI ID)
  • Public claims : 사용자가 정의할 수 있는 클레임 공개용 정보 전달을 위해 사용.
  • Private claims : 해당하는 당사자들 간에 정보를 공유하기 위해 만들어진 사용자 지정 클레임. 외부에 공개되도 상관없지만 해당 유저를 특정할 수 있는 정보들을 담는다

Signature : 시그니처에서 사용하는 알고리즘은 헤더에서 정의한 알고리즘 방식을 활용한다 시그니처 구조는 (헤더 + 페이로드)와 서버가 갖고있는 유일한 key값을 합친 것을 헤더에서 정의한 알고리즘으로 암호화 한다

Stateless, Stateful

Stateless(무상태)와 Stateful(상태 보존)를 간단하게 알아보자 Node.js 서버가 언제든 죽었다가 살아나도 똑같은 동작을 하면 StateLess하다고 볼 수 있다 반대로 서버가 죽었다가 살아났는데 조금이라도 다른 동작을 하는 경우 Stateful하다고 볼 수 있다

서버가 스스로 어떤 기억을 갖고 다른 결정을 하냐 마냐의 차이라고 보면 쉽다