NodeJS - Token 저장 위치의 고찰

김정욱·2020년 12월 13일
4

NodeJS

목록 보기
11/22
post-thumbnail

(여기서 언급하는 Token은 Access Token을 의미합니다)

Token은 어디에 저장해야 할까?

[ Token을 주고 받는 과정 ]

1. Client가 로그인에 성공하면 Server에서 Token을 발행해서 Response !
    (HTTP Response 메시지의 Body에 담아서 )
2. Client는 받은 Token을 저장해둔다
3. 인증이 필요한 Request가 있을 때 서버에 받은 Token을 보내서 인증한다 !


위 과정에서 우리는 메인 질문2가지 방향으로 볼 수 있다
1) 클라이언트는 받은 Token을 어디에 저장해야 하는지 ?
2) HTTP Request시 Cookie / Authorization 중 어디에 담아야 하는지 ?


Client는 Token을 어디에 저장할까?

(Android / IOS는 각각 다른 방식으로 저장하며 지식이 별로 없기 때문에 생략)
Web Client가 정보를 저장할 수 있는 공간은 크게 ' Cookie '' Web Storage '로 나눔


  • 쿠키는 HTTP 통신의 무상태성을 보완해주기 위해 나온 것
  • 서버가 보낸 data를 최대 4KB까지 저장하는 공간
  • 서버에서 접근할 수 있는 것이 가장 큰 특성 !
  • HTTP Request시 자동으로 포함된다는 특징이 있음
  • HttpOnly 설정을 추가하여 JavaScript의 접근을 막을 수 있음
    (Script를 이용하는 공격인 XSS를 차단 ! / CSRF공격에는 노출 !)

[ Web Storage ]

: Web StorageSession Storage / Local Storage 로 나뉜다

  • Web Storage는 서버에서 접근할 수 없다는 특징이 있음

1. Session Storage

  • 서버에서 접근할 수 없음
  • session cookies와 비슷! --> 세션을 위한 저장 공간
  • 세션이 종료되면 모두 삭제 (브라우저 종료시 삭제됨)
  • 5 ~ 10MB의 크기를 갖는 공간

2. Local Storage

  • 역시 서버에서 접근할 수 없음
  • persistent cookies와 비슷!
  • 반 영구적으로 저장 가능
  • 5 ~ 10MB의 크기를 갖는 공간

[ 그래서 어디에 저장하면 좋은가? ]

악의적인 Script를 삽입하는 XSS(cross-siste scripting)의 측면에서 볼 때
HttpOnly속성으로 JavaScript를 차단할 수 있는 ' Cookie '가 조금 더 보안에
좋을 수 있다.
(Web Storage는 JavaScript로 쉽게 접근이 가능하기 때문 !)
(그리고 Web Storage는 서버에서 접근할 수 없어 보낼 때 파싱해서 보내야 함 !)


(ref https://woowacourse.github.io/javable/2020-08-31/where_to_store_token)
(ref https://lazyhoneyant.tistory.com/7)

HTTP Request시 Token은 어디에?

Cookie / Authorization 은 모두 HTTP Request header내부에 있는 필드

사실 두 방법 모두 같은 곳에 있어서 보안성은 같다
즉, 개발자의 스타일 / 방식의 차이 !
(그래도 Authorization선호가 조금 더 많은 것 같다)


1. Cookie에 token넣기

: 어차피 Cookie를 이용할 것이라면 서버 측에서 토큰 발행 후 Cookie에 넣어 보내는 것이 좋음

(/routes/user.js) - 서버측에서 Cookie에 Token담아 보내기

...

/* x_auth라는 이름으로 유저의 토큰을 쿠키에 넣는 것 ! */
res.cookie("x_auth", user.token)
    .status(200)
    .json({ loginSuccess: true, userId: user._id })

(/middleware/auth.js) - 서버측에서 Client가 보낸 Request에서 토큰 파싱 하는 것 !

const { User } = require('../models/User');

let auth = (req, res, next) => {
    //인증 처리를 하는곳 
    //클라이언트 쿠키에서 토큰을 가져온다.
    let token = req.cookies.x_auth;
    // 토큰을 복호화 한후  유저를 찾는다.
    User.findByToken(token, (err, user) => {
        if (err) throw err;
        if (!user) return res.json({ isAuth: false, error: true })
        req.token = token;
        req.user = user;
        next();
    })
}

module.exports = { auth };

2. Authorization 필드에 Token 넣기

Client가 HTTP Response Body에서 받은 Token을 아래 처럼 많이 사용

Bearer {Token Description}
   ex) -> Bearer eyJhbadwdswsgkwq


(postman에서 입력시)


(서버에서 처리하는 방법)

...
if(
  req.headers.authorization &&
  req.headers.authorization.startWith('Bearer')
){
  /* 앞에 Bearer과 하나의 공백을 빼고 토큰 값만 파싱 ! */
  token = req.headers.authorization.split(' ')[1];
} /* 아래 부분은 혹시 쿠키에 토큰이 있는 경우를 대비해 처리 ! */
 else if (req.cookies.token){
  token = req.cookies.token;
}

[ 헷갈렸던 점 ]

나는 모바일 애플리케이션 개발을 진행할 때 req.headers에 token이라는 이름으로
token을 넣어서 주고받으며 프로젝트를 구현했었다.
그러나 token에 대해 알아보면서 cookie나 authorization 필드를 알게되면서
내가 그러면 잘못했던건가? 싶었다.
하지만 결국 HTTP Request Header를 이용하는
것은 같고, 그저 사용하는 변수만 달랐던 것이다. (보안성도 동일!)

현업에서는 저렇게 Authorization 이라는 필드를 통해 누가봐도 인증과 관련한 Token
이 있는 것을 통일하기 위해 사용할 뿐
이었다. 내가 틀린것은 아니었음 !

하지만 위에처럼 Bearer을 사용한 Token처럼 똑같이 header의 필드를 이용하지만
추가적인 선택지는 있었다.
아래 글에 자세히 나와있으니 참조하면 좋을 듯 !

(https://velog.io/@city7310/%EB%B0%B1%EC%97%94%EB%93%9C%EA%B0%80-%EC%9D%B4%EC%A0%95%EB%8F%84%EB%8A%94-%ED%95%B4%EC%A4%98%EC%95%BC-%ED%95%A8-5.-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%9D%B8%EC%A6%9D-%EB%B0%A9%EC%8B%9D-%EA%B2%B0%EC%A0%95)

profile
Developer & PhotoGrapher

0개의 댓글