🐈오늘 공부한 것
✔️Cookie & Session
Cookie 쿠키
쿠키란 HTTP 프로토콜이 가진 무상태성을 보완하기 위해 사용하는 데이터의 일종이다. HTTP가 stateless 라는 것은 서버가 이전에 받은 요청에 대해 기억하지 못하는 것을 의미한다. 이런 특성 때문에 클라이언트에서 미리 모든 정보를 담아 요청을 보내어 여러 서버가 많은 요청을 처리할 수 있다는 장점이 있다. 반면에 기억해줬으면... 하는 것들을 기억하지 못하기 때문에 쿠키라는 데이터에 기억해줬으면 하는 것들을 담아 서로 주고받으면서 상태를 유지할 수 있게 된다.
쿠키를 사용하기 위해서 서버가 클라이언트에 쿠키를 보내게 되면 브라우저가 쿠키를 가지고 있게 된다. 쿠키는 명시적으로 삭제하기 전까지는 브라우저에 보관되기 때문에 브라우저에 쿠키가 있고 도메인이 같은 경우에 첫 번째 요청과 함께 가지고 있는 쿠키를 함께 보낸다. 서버에서는 이 쿠키를 확인해 해당하는 데이터를 응답해주고 이렇게 이전의 상태를 기억할 수 있게 된다.
쿠키는 보안에도 취약하고 옵션에 따라서 script 태그로 접근할 수도 있어서 민감한 정보는 사용하지 않는 것이 좋다.
// 쿠키 옵션을 작성해 조건을 만들어 줄 수 있다.
const cookiesOption = {
// 도메인과 경로는 특정 도메인, 특정 경로에 해당할 때 쿠키가 전송되도록 한다.
domain: 'localhost',
path: '/',
// 이 옵션이 true 여야 script 태그로 접근할 수 없다.
httpOnly: true,
// cors를 허용하는 옵션이고, Lax와 Strict 옵션으로 get 요청이나 cors는 허용하지 않을 수 있음
sameSite: 'none',
// 위 옵션을 모두 허용(none)으로 지정하면 https 프로토콜을 사용해야만 쿠키를 사용하도록 한다.
secure: true,
};
// 조건에 따라 분기하여 아래와 같은 추가 옵션을 설정할 수 있다.
cookiesOption.maxAge = 1000 * 60 * 30; // 쿠키 유지 시간
// express 에서는 아래와 같이 cookie 메서드를 제공하고 있다.
// res.cookie(name, value [,options]) 순서로 전달하여 쿠키를 셋팅한다.
res.cookie('cookieId', userInfo.id, cookiesOption);
// 추가로 express에서 redirect는 아래와 같이 작성한다.
res.redirect('/userinfo');
// 쿠키 삭제
// 로그아웃 등 쿠키를 명시적으로 삭제하려면 clearCookie 메서드를 사용한다.
// 아래와 같이 작성하면 name 을 기준으로 하는 쿠키를 삭제함.
res.clearCookie('name', { path: '/' })
Session 세션
쿠키가 클라이언트에 데이터를 저장하는 것이라면, 세션은 서버에 데이터를 저장하고 클라이언트에게는 세션 id 라는 것을 부여해 요청시 쿠키에 담아 보내도록 한다. 주고 받을 때 쿠키를 사용한다는 것은 여전하지만 주고 받는 것은 암호화된 세션 id 이기 때문에 쿠키보다는 약간 보안이 더 좋다고 할 수 있다.
사용 방법은 쿠키랑 비슷한데 클라이언트의 첫 요청에 대해 서버가 세션 id를 쿠키에 담아 응답하면 다음 요청부터는 세션 id와 함께 요청을 보내고 서버에서는 이 세션 id가 유효한지를 확인해 서버에 기억하고 있는 인증 상태(세션)을 조회해 그에 맞는 데이터를 응답할 수 있다.
세션의 단점이라함은 쿠키가 클라이언트에 저장되어 있기 때문에 서버에는 부담이 없는 반면에 세션은 서버의 메모리에 위치하기 때문에 세션id 가 많이 발급되어(유저가 많아서) 세션이 메모리에 가득가득 하다면 그만큼 서버에도 부담이 되고 성능적으로 그렇게 좋지 못할 것이다.
node.js 에서는 express-session 이라는 미들웨어가 있어서 세션을 관리할 수 있다.
// 특정 요청이 왔을 때 아래와 같이 세션 아이디를 설정할 수 있다.
// 쿠키와의 차이점은 req.session 이라는 객체를 사용한다는 것이다. express-session을 사용할 때의 규칙.
req.session.sessionId = userInfo.id;
// 세션도 쿠키에 속해있어서 아래와 같이 쿠키 유효시간을 추가해줄 수 있다.
req.session.cookie.maxAge = 1000 * 60 * 30;
// 위와 같이 세션 아이디를 설정해주면 리다이렉트 된 다른 엔드포인트에서 아래와 같이 접근할 수 있다.
const sessionId = req.session.sessionId;
// 위 세션 아이디를 가지고 db에 존재하는 특정 데이터를 조회해 일치하는 것이 있다면 해당 데이터를 응답한다.
// 로그아웃 등 세션을 삭제하려면 아래와 같이 한다.
req.session.destroy();
express를 가지고 쿠키와 세션을 사용하는 서버 코드는 위와 같다. 핵심은 이런 도구를 가지고 어떤 플로우로 기능이 구현되는가를 이해해야 한다. 오늘 과제에서도 그 부분이 잘 정리되지 않아서 더 어렵게 느껴졌던 것 같다.
아주 간단한 로그인 - 로그인유지 - 로그아웃 기능을 가진 앱을 구현한다면 아래와 같은 플로우를 가질 것이다.
상당부분 간소화를 했지만... 세션 id를 주고받으면서 (만약 유효한 세션id가 브라우저에 있다면) 요청과 함께 보내서 기존 상태에 해당하는 데이터를 받을 것이고, 아니라면 로그인과 동시에 세션 id를 발급 받을 것이다.
✔️HTTPS
앞서 설명했듯 쿠키, 세션을 사용하기 위해서는 SSL/TLS 프로토콜로 통신 암호화가 이루어지는 HTTPS 프로토콜을 사용한다. 서버가 CA(인증서 발급 기관)에서 서버 공개키와 서버 정보를 제공해 인증서를 받아오면, 클라이언트가 요청할 때 인증서를 보내주고 클라이언트에서는 브라우저에 내장된 CA 공개키를 가지고 이 인증서를 복호화하여 정보와 서버 공개키를 가지게 된다. 여기서 클라이언트가 제대로 복호화 할 수 없는 인증서가 신뢰할 수 없는 인증서가 되는 것이다.
이렇게 복호화가 이루어지고 난 다음에는 클라이언트와 서버가 각각 대칭키를 가지고 암호화 복호화를 하여 응답과 요청을 주고 받게 된다. 이렇게 되면 중간에 키가 탈취될 가능성도 적고 데이터도 암호화 되어 오고 가기 때문에 일반 HTTP 보다 보안에 훨씬 강해지게 된다.
일반적으로 외부 CA 기관에서 인증서를 발급받겠지만, 로컬 개발환경에서 내 컴퓨터 자체가 CA가 되어서 인증서를 발급해 HTTPS 프로토콜을 사용하는 방법도 있는데 그게 바로 mkcert 라이브러리를 사용하는 것이다. mkcert를 사용하면 내 컴퓨터를 인증 기관으로 등록하고 인증서와 인증 키를 발급해주게 되는데 로컬 환경에서 https 서버를 구축할 때 발급 받은 파일을 함께 전달하여 사용한다.
+ 윈도우, wsl2 우분투 환경에서 mkcert 사용하기.
나는 현재 윈도우에서 wsl2를 사용해 우분투 환경에서 개발을 하고 있다. 이런 환경에서 mkcert 라이브러리를 사용하려면 윈도우와 우분투 환경 모두 CA 로 등록하고 같은 인증서를 사용해야 제대로 동작하는 것 같다. 아래 참고 링크가 있지만 해결 방법을 간단하게 작성하자면,
1. 먼저 윈도우 로컬 환경에서 choco로 mkcert를 설치하고 CA로 등록한다. 이 과정에서 안랩 같은 보호 프로그램이 동작하면 인증서 등록이 중단될 수 있기 때문에 별도 설정이 필요할 수도 있다.
2. 우분투 환경에서도 mkcert -install 명령어로 CA 등록을 해준다.
3. 윈도우와 우분투에서 각각 mkcert -CAROOT 명령어를 입력하면 방금 발급받은 인증서 위치를 확인할 수 있는데, 윈도우에 위치한 파일을 우분투의 같은 디렉토리로 덮어씌운다.
4. 그리고 난 뒤 https 서버 디렉토리에 가서 아래와 같이 입력해 key.pem 과 cert.pem을 발급받는다.
mkcert -key-file key.pem -cert-file cert.pem localhost 127.0.0.1 ::1
5. 여기까지 한 뒤에 https 프로토콜로 로컬호스트 경로에 접속하면 정상적으로 동작하는 것을 확인할 수 있다.
참고링크 : https://www.haveiplayedbowie.today/blog/posts/secure-localhost-with-mkcert/
이런 사전 과정이 없어서 에러를 많이 겪었는데, 처음에는 https 가 제대로 동작하지 않아서 생기는건지 모를 정도였다. 그냥 서버가 제대로 열리지 않으면서 콘솔창에는 별다른 에러 메시지 없이 `crbug/ non-js module files deprecated` 라는 문구만 있었는데, 여기에 꽂혀서 수십 건의 게시글을 봤지만 별다른 해결책을 찾을 수 없었다 ㅜㅜ. 그러다가 mkcert를 사용하기 전 http만 사용할 때는 제대로 동작하는데, https 서버가 되면서 이 에러가 발생하는 것을 보고 내가 wsl2 환경에서 서버를 구동하면서 윈도우 환경에서 https 프로토콜로 접근을 하는게 원인일 것 같다고 생각해 해당 키워드로 구글링을 했다. 이 방법으로 제대로 해결이 되지 않을 가능성도 있는데, wsl과 mkcert를 사용한다면 아마 이 문제일 가능성이 높은 것 같다.
🐈더 공부할 것
1. Next.js
2. 슬라이딩 윈도우, 해쉬 알고리즘 학습 **
3. 토큰 인증
🐈오늘의 느낀 점
1.오늘은 mkcert 인증서 관련 에러를 해결하느라 정규 과정을 제대로 하질 못해서... 늦은 시간까지 과제를 했다. 로컬 환경에서 발급하는게 아니라 다른 외부 기관에서 발급하는 것이라면 이런 에러가 발생하지 않았을 것 같은데 (혹은 윈도우 아님 우분투 하나의 환경에서만 개발하거나...), 두 개의 환경에서 따로따로 개발하고 있다는 것이 문제라는걸 꽤나 늦게 깨달았다. 구글링하면서 인증서 관련 내용과 용어들이 너무 어렵게 느껴져서 살짝 포기하고 싶었는데, 해결한 뒤에 너무 기뻐서 그런 생각이 쏙 들어갔음.
'TIL' 카테고리의 다른 글
[Day 61] 2022-0915: oAuth 깃허브 인증, Next.js (0) | 2022.09.16 |
---|---|
[Day 60] 2022-0914: JWT 로그인 인증 구현, Next.js (0) | 2022.09.15 |
[Day 58] 2022-0912: Next.js (0) | 2022.09.13 |
[Day 57] 2022-0909: Next.js , 알고리즘 (0) | 2022.09.09 |
[Day 56] 2022-0908: 네트워크, 요즘 느끼는 것 (0) | 2022.09.09 |