(해석 또는 이해가 잘못된 부분이 있다면 댓글로 편하게 알려주세요.)
HTTP defines several ways for a server to specify how long a document can be cached before it expires. In decreasing order of priority, the server can:
• Attach a Cache-Control: no-store header to the response.
• Attach a Cache-Control: no-cache header to the response.
• Attach a Cache-Control: must-revalidate header to the response.
• Attach a Cache-Control: max-age header to the response.
• Attach an Expires date header to the response.
• Attach no expiration information, letting the cache determine its own heuristic expiration date.
This section describes the cache controlling headers. The next section, “Setting Cache Controls,” describes how to assign different cache information to different content.
이번 섹션에서는 캐시 제어 헤더에 대해 설명합니다.
다음 섹션인 "Setting Cache Controls"에서는 서로 다른 콘텐츠에 대해 캐시 정보를 다르게 설정하는 방식에 대해 설명합니다.
HTTP/1.1 offers several ways to limit the caching of objects, or the serving of cached objects, to maintain freshness. The no-store and no-cache headers prevent caches from serving unverified cached objects:
Cache-Control: no-store
Cache-Control: no-cache
Pragma: no-cache
HTTP/1.1은 Freshness를 유지하기 위해 오브젝트를 캐싱하거나 캐싱된 오브젝트를 제공하는 것을 제한하는 방법들을 제공하고 있습니다.
no-store 및 no-cache 헤더는 검증되지 않은 캐싱 오브젝트를 제공하는 것을 방지합니다.
Cache-Control: no-store
Cache-Control: no-cache
Pragma: no-cache
A response that is marked "no-store" forbids a cache from making a copy of the response. A cache would typically forward a no-store response to the client, and then delete the object, as would a non-caching proxy server.
"no-store"로 표시된 응답은 캐시가 응답으로부터 사본을 생성하는 것을 막습니다.
일반적으로 캐시는 비캐싱 프록시 서버와 마찬가지로 클라이언트에게 no-store 응답을 그대로 전달한 후 오브젝트를 삭제합니다.
A response that is marked "no-cache" can actually be stored in the local cache storage. It just cannot be served from the cache to the client without first revalidating the freshness with the origin server. A better name for this header might be "do-not-serve-from-cache-without-revalidation."
"no-cache"로 표시된 응답은 실제로 로컬 캐시 스토리지에 리소스를 저장할 수 있습니다.
그러나 원본 서버에서 Freshness를 재검증하지 않으면 캐시에서 클라이언트로 해당 리소스를 제공할 수 없습니다.
이 헤더에 더 적합한 이름은 "do-not-serve-from-cache-without-revalidation(재검증 없이 제공 불가)"일지도 모릅니다.
The Pragma: no-cache header is included in HTTP/1.1 for backward compatibility with HTTP/1.0+. HTTP/1.1 applications should use Cache-Control:no-cache, except when dealing with HTTP/1.0 applications, which understand only Pragma: no-cache.*
Pargma: no-cache 헤더는 HTTP/1.1에 포함되어 있습니다. 이전 버전인 HTTP/1.0+과의 호환성을 유지하기 위함입니다.
Pragma:no-cache만 이해할 수 있는 HTTP/1.0 응용 프로그램을 처리하는 것이 아니라면 HTTP/1.1 응용 프로그램은 Cache-Control:no-cache 헤더를 사용해야 합니다.
The Cache-Control: max-age header indicates the number of seconds since it came from the server for which a document can be considered fresh. There is also an s-maxage header (note the absence of a hyphen in “maxage”) that acts like max-age but applies only to shared (public) caches:
Cache-Control: max-age=3600
Cache-Control: s-maxage=3600
Cache-Control: max-age 헤더는 원본 서버에서 응답이 온 후로 몇 초 동안을 Fresh 하다고 여길 것인지를 나타냅니다.
max-age처럼 동작하지만 Shared Cache에서만 동작하는 s-maxage 헤더라는 것도 있습니다. 이 헤더는 maxage 사이에 하이픈(-) 기호가 없음에 유의합니다.
Cache-Control: max-age=3600
Cache-Control: s-maxage=3600
Servers can request that caches either not cache a document or refresh on every access by setting the maximum aging to zero:
Cache-Control: max-age=0
Cache-Control: s-maxage=0
Cache-Control: max-age=0
Cache-Control: s-maxage=0
The deprecated Expires header specifies an actual expiration date instead of a time in seconds. The HTTP designers later decided that, because many servers have unsynchronized or incorrect clocks, it would be better to represent expiration in elapsed seconds, rather than absolute time. An analogous freshness lifetime can be calculated by computing the number of seconds difference between the expires value and the date value:
Expires: Fri, 05 Jul 2002, 05:00:00 GMT
현재는 잘 사용되지 않는 Expires 헤더는 초 단위의 시간 대신 실제 만료 일시를 나타냅니다.
HTTP 설계자들은 시간이 흐르고 나서야 만료 일시를 절대 시간보다는 경과된 초 단위로 나타내는 것이 더 낫다는 것을 알게 됩니다. 많은 서버들이 동기화되지 않은 부정확한 시계를 사용하고 있었기 때문입니다.
Freshness의 생명주기는 Expires의 값과 Date의 값을 비교하여 연산될 수 있습니다.
Some servers also send back an Expires: 0 response header to try to make documents always expire, but this syntax is illegal and can cause problems with some software. You should try to support this construct as input, but shouldn’t generate it.
어떤 서버는 문서를 항상 만료 상태로 두기 위해 Expires: 0 응답 헤더를 반환하기도 합니다.
하지만 이것은 잘못된 문법으로, 일부 소프트웨어에서는 문제를 발생시킬 수 있습니다.
개발자들은 이러한 잘못된 형태도 지원할 수 있어야 하지만 직접 생산해서는 안 됩니다.
Caches may be configured to serve stale (expired) objects, in order to improve performance. If an origin server wishes caches to strictly adhere to expiration information, it can attach a Cache-Control:
Cache-Control: must-revalidate
캐시는 성능을 향상시키기 위해 Stale 오브젝트를 제공하도록 구성될 것입니다.
만약 캐시가 만료에 대한 정보를 엄격하게 준수하길 원한다면 Cache-Control에 must-revalidate를 붙일 수 있습니다.
Cache-Control: must-revalidate
The Cache-Control: must-revalidate response header tells caches they cannot serve a stale copy of this object without first revalidating with the origin server. Caches are still free to serve fresh copies. If the origin server is unavailable when a cache attempts a must-revalidate freshness check, the cache must return a 504 Gateway Timeout error.
Cache-Control: must-revalidate 응답 헤더는 캐시가 오브젝트의 만료된 사본을 원본 서버로부터의 재검증 없이 제공하지 못하도록 합니다.
물론 여전히 캐시는 Fresh한 사본들을 제공하는 것에 자유롭습니다.
캐시가 must-revalidate에 따라 Freshenss Check를 요청하였지만 원본 서버를 이용할 수 없는 상황이라면, 캐시는 504 Gateway Timeout 에러를 반환해야 합니다.
캐싱된 문서의 "Fresh" 기간을 원본 서버가 정의하기 위한 몇 가지 방식
Cache-Control: no-store
Cache-Control: no-cache
Pragma: no-cache
Cache-Control: max-age=3600
Cache-Control: s-maxage=0
Expires: Fri, 05 Jul 2002, 05:00:00 GMT
Expires: 0 (잘못된 형태)
Cache-Control: must-revalidate
오늘 배운 헤더들 사실 개발하면서 많이 봤던 것들이다. 딱히 이 헤더들을 다룰 일도, 이 헤더 때문에 문제가 발생했던 적도 없어서 그저 항상 존재하는 공기처럼 취급했던 것뿐이다. 당연하다. Cache-Control이 어떻게 설정되어 있고 Expires가 어떻게 설정되어 있든 응답이 오는 데는 아무런 문제가 없다.
하지만 내가 오늘 이 글을 읽지 않고 이 헤더들을 평생 모르고 살았다면 언젠가 최적화에 문제가 발생했을 때 떠올릴 수 있는 묘수 하나가 없어지는 셈이다. 물론 그때가 되면 내가 오늘 읽은 모든 내용을 기억하지는 못하겠지만, 이미 알고 까먹은 것과 아예 모르는 것은 천지 차이라고 하지 않는가. 모든 상식들이 그렇듯 어렴풋이라도 기억해서 요긴하게 써먹을 날이 올지도 모른다.
글을 마치려다 갑자기 그런 생각이 들었다. 캐시는 보안상 좋기도 하고 응답 지연을 해소해주는 아주 좋은 녀석이라고 알고 있다. 그런데 no-store와 no-cache라는 옵션이 있는 것을 보면 캐시를 사용하는 게 항상 좋은 것은 아닌 걸까?
앞에서 우리는 프록시에 대해 이미 배웠다. 그리고 나는 캐시도 기본적으로 프록시니까 보안 측면에서 더 좋을 것이라고 안일하게 생각했다. 하지만 얼마 지나지 않아 이 발언이 얼마나 멍청한 것인지를 깨닫게 되었다...ㅋㅋㅋㅋ 캐시는 프록시의 충분조건이지 필요조건이 아니라는 뜻이다.
프록시가 Firewall이나 Anonymizer처럼 동작한다면 트래픽을 검열한다거나 HTTP 메시지에서 식별 특성을 삭제하는 등의 조치를 취할 것이다. 그렇기 때문에 프록시가 보안상 이점이 있다는 설명이 들어가게 된 것이다. 하지만 일반적인 웹 캐시에서는 특수한 보안 조치를 기대하기는 어렵다(물론 요즘 웹 캐시들은 잘 나와서 보안 기능이 있는 것도 많다). 기껏해봐야 부하 분산에 의한 DDos 공격의 완화 정도라고 볼 수 있다. 웹 캐시는 트래픽을 암호화할 이유도 없을 뿐더러 보안보다는 빠른 리소스 제공에 더 초점을 맞추어야 하는 프록시다.
그럼 여기서 웹 캐시를 해킹하면 어떤 상황이 벌어질까?
웹 캐시가 공격을 당했을 때 노출되는 정보는 전송된 트래픽과 클라이언트의 IP 주소, 그리고 캐싱된 리소스들이다. 만약 웹 캐시로 민감한 정보가 전송되었고 심지어 저장까지 되었다면 개인정보 유출로 뉴스에 박제되는 수가 있다. 따라서 금융 정보나 로그인 세션 정보 등 민감한 정보들은 반드시 no-store 옵션을 붙여 웹 캐시에 저장되지 않도록 해야 한다. 민감 정보들이 웹 캐시에 저장되어 있지 않기만 해도 웹 캐시가 털렸을 때(?) 입는 피해는 상당히 줄어든다. 응답 시간만 쪼~금 늘어날 뿐이다.
아무튼 그런 점에서 no-cache와 no-store 옵션은 굉장히 중요하다!!