안녕하세요. 이번 시간에는 쿠키 & 캐시 전용 헤더만 따로 알아보겠습니다. 웹 자원을 효율적으로 쓰기 위해서는 캐싱이 중요합니다. 똑같은 데이터를 계속해서 내려 받을 필요는 없죠. 쿠키는 클라이언트(프론트)와 서버 간에 데이터를 주고받는 가장 간단한 방법 중 하나입니다. 이런 것들에 대한 설정을 헤더를 통해 할 수 있습니다. 쿠키나 캐시에 대한 정보는 개발자 도구(크롬 기준)의 Application 탭에서 쉽게 확인할 수 있습니다.
캐시
여기서 말하는 캐시는 개인 캐시를 뜻합니다. CDN같은 공유 캐시가 아니라요. 여러분의 브라우저에 응답으로 온 HTML이나 JSON같은 데이터가 저장되어 나중에 서버에 요청을 보내지 않고도 브라우저에 저장된 응답을 사용할 수 있습니다.
보통 캐싱은 GET 요청에만 합니다. GET이 REST적의미로 가져오다이기 때문에, 가져온 데이터를 저장해두고 두고두고 쓰는 것이죠. 다른 요청 메서드를 캐싱하는 것을 잘 보지 못했습니다. 복잡한 경우는 제외하고요. 일반적으로 200(가져오기 성공), 301(다른 주소로 이동 후 가져옴), 404(가져올 게 없음) 상태 코드로 온 응답을 캐싱할 수 있습니다.
Cache-Control
많은 옵션들이 있지만, 자주 쓰이는 옵션만 알아봅니다.
먼저 아무것도 캐싱하지 않으려면
Cache-Control: no-store
를 하면됩니다. 또는 no-cache, no-store, must-revalidate로 no 시리즈를 다 붙여줍니다.
Cache-Control: no-cache
는 가장 많이 헷갈려하는 헤더 설정인데요. no-cache이지만 cache하지 말라는 뜻이 아닙니다!!! 모든 캐시를 쓰기 전에 서버에 이 캐시 진짜 써도 되냐고 물어보라는 뜻입니다.
Cache-Control: must-revalidate
must-revalidate는 만료된 캐시만 서버에 확인을 받도록 하는 겁니다. no-cache랑 must-revalidate는 이름이 잘못 지어진 감이 있습니다.
Cache-Control: public 또는 private
public이면 공유 캐시(또는 중개 서버)에 저장해도 된다는 뜻이고 private이면 브라우저같은 특정 사용자 환경에만 저장하라는 뜻입니다.
Cache-Control: public, max-age=3600
max-age로 캐시 유효시간을 줄 수 있습니다. 초 단위이므로 위 예제에서는 1시간입니다. 1시간이 지나면 이 응답 캐시는 만료된 것으로 여겨집니다.
참고로 위의 옵션들은 혼합해서 써도 됩니다. no-store, no-cache, must-revalidate처럼 콤마로만 구분하면 되고요.
Cache-Control을 응답 헤더라고 생각하실 수도 있는데, 요청 헤더로도 사용할 수 있습니다. 프론트 - 중개 서버 - 진짜 서버와 같은 구조인 경우에 중개 서버에 있는 캐시를 가져오지 않도록 하려면 요청 시부터 Cache-Control을 헤더로 넣어주곤 합니다.
Age
Age 헤더는 캐시 응답 때 나타나는데, max-age 시간 내에서 얼마나 흘렀는지 초 단위로 알려줍니다. 위 예제에서 max-age= 3600을 설정한 경우, 1분이 지나면
Age: 60
이 캐시 응답 헤더에 포함됩니다.
Expires
Cache-Control과 별개로 응답에 Expires라는 헤더를 줄 수도 있습니다.
Expires: Thu, 26 Jul 2018 07:28:00 GMT
응답 컨텐츠가 언제 만료되는지를 나타내며, Cache-Control의 max-age가 있는 경우 이 헤더는 무시됩니다.
ETag
HTTP 컨텐츠가 바뀌었는지를 검사할 수 있는 태그입니다. 같은 주소의 자원이더라도 컨텐츠가 달라졌다면 ETag가 다릅니다. 예를 하나 들어봅시다.
GET www.zerocho.com의 응답 본문이 안녕 제로초이고 ETag 헤더 값이 12345라 칩시다. 만약 서버 컨텐츠(응답 본문)가 동일하다면 매번 GET www.zerocho.com을 할 때마다 ETag는 12345입니다. 그런데 안녕 제로초에서 안녕 이태그로 컨텐츠가 바뀌었다면 ETag 헤더 값도 34567로 바뀝니다. 그러면 서버가 클라이언트의 응답 내용이 달라졌구나를 깨닫게 되어 캐시를 지우고 새로 컨텐츠를 내려받을 수 있게 됩니다.
Etag: W/"3bf2-wdj3VvN8/CvXVgafkI30/TyczHk"
If-None-Match
서버보고 ETag가 달라졌는 지 검사해서 ETag가 다를 경우에만 컨텐츠를 새로 내려주라는 뜻입니다.
If-None-Match: W/"3bf2-wdj3VvN8/CvXVgafkI30/TyczHk"
만약 ETag가 같다면 서버는 304 Not Modified를 응답해서 캐시를 그대로 사용하게 합니다.
쿠키
쿠키는 브라우저에 저장되는 작은 데이터 조각으로, 임시 데이터 보관 또는 웹페이지 개인화 등에 사용됩니다. 쿠키를 주기적으로 지우지 않으면 브라우저에 엄청나게 많은 쿠키들이 쌓여 있는 것을 보게 되실텐데 이것들이 여러분을 추적하고 있는 것입니다.
Set-Cookie
서버에서 클라이언트(브라우저)한테 이런 이런 쿠키를 저장하라고 명령하는 응답 헤더입니다.
Set-Cookie: 키=값; 옵션들
Set-Cookie: hello=zero면 hello라는 키에 값을 zero로 해서 보낼 수 있는거죠. 옵션들도 몇 개 알려드리겠습니다.
- Expires: 쿠키 만료 날짜를 알려줄 수 있습니다.
- Max-Age: 쿠키 수명을 알려줄 수 있습니다. Expires는 무시됩니다.
- Secure: https에서만 쿠키가 전송됩니다.
- HttpOnly: 자바스크립트에서 쿠키에 접근할 수 없습니다. XSS 요청을 막으려면 활성화해두는 것이 좋습니다.
- Domain: 도메인을 적어주면 도메인이 일치하는 요청에서만 쿠키가 전송됩니다. 가끔 도메인이 다른 쿠키들이 있는데, 이런 쿠키들은 써드 파티 쿠키로 여러분을 추적하고 있는 쿠키입니다. 구글이나 페이스북같은 곳이 써드 파티 쿠키를 적극적으로 사용합니다.
- Path: 패스를 적어주면 이 패스와 일치하는 요청 요청에서만 쿠키가 전송됩니다.
예를 들면 다음과 같이 가능합니다.
Set-Cookie: zerocho=babo; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
쿠키는 XSS 공격과 CSRF 공격 등에 취약하기 때문에 HttpOnly 옵션을 켜두고, 쿠키를 사용하는 요청은 서버 단에서 검증하는 로직을 꼭 마련해두는 것이 좋습니다.
Cookie
반대로 클라이언트가 서버한테 쿠키를 보내줄 때는 이 요청 헤더에 담아 보냅니다.
Cookie: 키=값; 키=값;
서버는 이 쿠키 헤더를 파싱해서 사용하게 됩니다. 아까도 말했듯 CSRF 공격같은 것을 막기 위해서 반드시 서버는 쿠키가 제대로 된 상황에서 온 것인지 확인하는 로직을 갖춰야 합니다.
이렇게 캐시와 쿠키에 관련된 헤더를 알아봤습니다. 보통은 서버가 알아서 세팅하는 캐시와 쿠키를 사용하지만, 여러분이 수정해야할 때도 있습니다. 그 때 참조하시면 될 것 같습니다.
다음 시간에는 X로 시작하는 헤더들에 대해 알려드리겠습니다!