etc...

[etc] HTTP Cache

빛나유 2015. 1. 5. 16:22

HTTP는 보안 업무를 하는 중 가장 많이 보는 것 중에 하나다. 대부분의 공격이 웹공격을 통해서 이루어지기 때문이다. 그런데 사실, 실무에서 GET, POST, PUT, HEAD가 대충 어떤 식의 기능을 하는지, 200, 300, 400, 500 대의 응답이 어떤 성격을 가진 응답인지, 필드명 부분에 대해서는 Host, X-Forwarded-For, Referer 이 정도만 알아도 대략의 분석이 가능하다. (조금 과장해서 말하면...)


HTTP에 대해서 조금 더 자세하게 알 필요가 있다고 생각했다. 이번 기회에 공부해보자. 어마어마한 내용이 기다리고 있다. 기대하시길...


우선, HTTP에 대해서 두 부분으로 나눠서 설명할 생각이다. 

1. HTTP Cache

2. HTTP Method, Field, Status


생각보다 HTTP에서 Cache는 많은 내용을 차지하고 있다. 120페이지 가량되는 RFC문서의 1/6을 차지하고 있고, 50여개의 HTTP Field 중 상당수가 HTTP Cache를 위해서 존재한다. 아무튼 위에서 소개한 대로 HTTP Cache에 대해서 먼저 공부를 시작해보자.

========


기본적으로 HTTP Cache는 웹서버로 하여금 일을 최대한 적게 하기 위한 방법이다

가령, index.html client가 요청했을 때 server는 그거에 대한 응답을 했을 것이다. 그런데 client server에게 index.html을 또 요청하면, server 입장에서는 아까 줬던 것을 또 줘야 하는 비효율이 발생하게 된다. 아 그러면 무조건 client server에게 받은 것을 cache(client PC어딘가..) 저장해두면 된다. 그러면 굳이 server client에게 똑같은 것을 다시 보내주지 않아도 된다.

 

이러면 이런 문제가 발생하게 된다.

제일 처음에 clientindex.html을 요청을 해서 server가 응답을 해줬는데, 그리고 server index.html 내용을 수정할 필요가 있어서 내용 수정을 했다다시 Client index.html을 요청할 때, “? 난 이미 내 cache index.html이 있네?” 하고 cache에 저장되어있는 것을 다시 쓴다면? 문제가 생기게 된다. server가 가지고 있는 index.html은 이미 한번 수정이 된 것이다. 그러니까 수정되기 이전의 index.html, , client cache에 저장해둔 그 index.html은 최신 정보가 아니다.

 

이런 문제를 해결하기 위해 HTTP에서는 아래와 같은 field를 통해 문제를 해결한다. 그게 RFC2616 문서 13에 자세하게 나와있는 것이다.

보통 cache 관련된 HTTP Header Field는 아래와 같은 것들이 있다.

l  Cache-Control

l  Etag

l  If-XXX field ( i.e. If-Match, If-Modified-Since, etc)

l  Last-Modified

위의 4개가 가장 대표적인 Field이고 그 이외에 다른 것들도 있을 수 있다.

자 그러면 조금 더 구체적으로 각각의 필드에 대해서 이야기 해보면..

 

# Cache-Control

아래와 같은 형식을 하고 있다.

Cache-Control: 하나 이상의 cache-directive

 

cache-directive, cache-request-directive 또는 cache-response-directive 둘 중 하나인데, 각각이 무엇이냐, Cache-Control에 나올 수 있는 값들이 아래와 같다는 것이다.

 

cache-request-directive :

"no-cache" ; Section 14.9.1

"no-store" ; Section 14.9.2

"max-age" "=" delta-seconds ; Section 14.9.3, 14.9.4

"max-stale" [ "=" delta-seconds ] ; Section 14.9.3

"min-fresh" "=" delta-seconds ; Section 14.9.3

"no-transform" ; Section 14.9.5

"only-if-cached" ; Section 14.9.4

cache-extension ; Section 14.9.6

 

cache-response-directive :

"public" ; Section 14.9.1

"private" [ "=" <"> 1#field-name <"> ] ; Section 14.9.1

"no-cache" [ "=" <"> 1#field-name <"> ]; Section 14.9.1

"no-store" ; Section 14.9.2

"no-transform" ; Section 14.9.5

"must-revalidate" ; Section 14.9.4

"proxy-revalidate" ; Section 14.9.4

"max-age" "=" delta-seconds ; Section 14.9.3

"s-maxage" "=" delta-seconds ; Section 14.9.3

cache-extension ; Section 14.9.6

cache-extension = token [ "=" ( token | quoted-string ) ]

 

이런 식으로 정의되어 있다. 위의 내용은 RFC 문서 그대로 복사한 것이다.

 

위의 내용들이 무엇을 의미하는지 이해를 하려면 조금 더 이론을 공부해야된다.

그 내용들을 제대로 설명해둔 웹사이트들을 찾았는데

https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#cache-control

http://www.mobify.com/blog/beginners-guide-to-http-cache-headers/

 

영어로 된 포스팅이지만, 조금 시간이 걸려도 읽을만한 가치가 충분히 있다!! !! 시간내서 읽으시길 권유한다. 설명 진짜 쉽게 잘 해놓은 듯하다.


Etag는 

# Etag

http://en.wikipedia.org/wiki/HTTP_ETag

In typical usage, when a URL is retrieved the web server will return the resource along with its corresponding ETag value, which is placed in an HTTP "ETag" field:


ETag: "686897696a7c876b7e"


The client may then decide to cache the resource, along with its ETag. Later, if the client wants to retrieve the same URL again, it will send its previously saved copy of the ETag along with the request in a "If-None-Match" field.


# Request

GET /XXXXXX/ver3/event/app/left_banner3_on.gif HTTP/1.1
Accept: */*
Referer: http://www. XXXXXX.com/app/event/event.asp
Accept-Language: ko-KR
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)
Host: image. XXXXXX.com
If-Modified-Since: Wed, 17 Dec 2014 09:41:20 GMT
If-None-Match: "60a5fb9cdd19d01:dbe"
Connection: Keep-Alive
Cookie: _ga=GA1.2.624816863.1413303109; g%5F19con=N; adult=Y; Pm%5Fgoods=N; nick= XXXXXX; UID= XXXXXX; fg%5Fuserid= XXXXXX; xx= XXXXXX; cmn%5Fcash=0; Pm%5FBuycnt=0; FGUSR=BsW0HHfc64LOPdLe36mZQ1H576PSHLXcrQasR0DeLKLUPdT50sOiQ1Li1MW7HGrcGaK7PbveNcnqQ555SsPtHNDcT6XKR7HeIqLVPbz5SsPUQ21i0sWWHIvc8aLpPdHeLcnrQ7r5SsPtHGDcB6WLR7DeLaLpPWT50MOsQ51iTMXzHR3K8qKnPdreKMmlQ0156cOOHGPcCsWKR2Pe2qLVPbj5KMPzQ3ziTMXBHNDcN4LOPdLeIsnqQ2X5BcOgHIvc0sXzR5veLaLSPbn5M6OIQ5Pi2sW; premium%5Ffg=F; Wsn%5Fid=jkfirst6000; PCID=14189560905240012242501; RC_R=1920*1080; RC_C=32


# Response

HTTP/1.1 304 Not Modified

Server: Microsoft-IIS/5.0

Date: Fri, 19 Dec 2014 06:53:06 GMT

X-Powered-By: ASP.NET

P3P: CP="ALL DSP COR CURa ADMa DEVa TAIa IVAa IVDa CONa HISa TELa OUR DELa BUS"

ETag: "60a5fb9cdd19d01:dbe"

Content-Length: 0


ETag는 위와 같이 쓰인다. 요청에서 If-None-Match: "60a5fb9cdd19d01:dbe"와 같이 “이런 hash값을 가지고 있는 resource가 서버에 있니?”라고 물어보면 서버는 “아~ 있어!! 내가 굳이 다시 안 보내줘도 되겠네” 하고 304 “not modified” 응답!! “변한 것 없음ㅎ” “Cache에 있는 거 쓰삼ㅎ”하고 보내주는 것이다. 


즉, 내용이 변한 것에 대해서만 서버는 다시 response를 보내주면 되고(이런 경우 변한 내용이 response에 포함되어야한다.) 내용이 변하지 않은 것들은 굳이 다시 보내주지 않아도 cache에 있는 것을 쓰라고 304, Not Modified를 보내주면 되는 것이다. 따라서, If-None-Match와 ETag는 같이 쓰이면 네트워크 트래픽을 줄일 수 있다. 


If-None-Match는 이런 식으로 쓰이는데, If-Match는 어떻게 쓰일까? 이거는 반대다.

# Request

PUT /people/alessandro-nadalin HTTP/1.1 

If-Match: yuf8ew98ehf9h9h

Host: italianpeople.com


person:

  name:     Alessandro

  surname: Nadalin

company: DNSEE


# Response

HTTP/1.1 412 Precondition Failed

…..


Request에 있는 entity에(person ….. DNSEE) 대한 Etag값이 yuf8ew98ehf9h9h인데, 이것과 같은 것이 있으면 PUT하라는 것이다. 그런데 서버가 응답에서 Precondition Failed(412)를 보냈다면, “야~ 이미 같은거 있어~ 또 안해도 돼” 라고 말하는 것이다. 이미 있는 것을 굳이 덮어 씌울 필요 없다는 것이다. 그러면 그런 것은 어디에서 쓸까요?


이런 건 보통, 개발 서버에서 많이 쓴데요. 개발서버에 올려져있는 소스코드와 다를 경우만 업데이트 하도록 하기 위해서이죠. 업데이트를 하는데 기존과 내용이 같으면 굳이 하지 않아도 되잖아요? 그런거에요.


이런 건 보통, 개발 서버에서 많이 쓴데요. 개발서버에 올려져있는 소스코드와 다를 경우만 업데이트 하도록 하기 위해서이죠. 업데이트를 하는데 기존과 내용이 같으면 굳이 하지 않아도 되잖아요? 그런거에요. 우리 센터에서 HTTP Cache는 어떤 식으로 쓰일까요?



CDN Network라고 들어보셨는가? 못 들어봤다면… 아카마이는 들어봤는가? 아카마이는 회사 이름이다. CDN 서비스를 하는 회사이름이다. CDN이 뭐냐면. Content Delivery Network의 약자이다. 여기서 말하는 Content는 HTTP 응답에 나오는 Response Body나 등등 여러가지 정보를 의미한다. Cache 역할을 이 CDN에서 대신 해주는것이다. 


ABCDEF라는 회사가 아카마이 Cache server 서비스를 받는 회사라면, 내가 도메인 ABCDEF에 접근을 할 때,

GET /index.html HTTP/1.1

Host: www.ABCDEF.com


이라고 보내면 이것은 사실, 중간에 아카마이 Cache server를 거쳐서 간다. Index.html이 변했는지 판단을 아카마이 Cache Server에서 대신 해주는 셈이다. 


Request: Client → 아카마이 → Hyundai서버

Response: Client ← 아카마이 ← Hyundai서버


이렇게 왔다갔다 하는 것이다. 아카마이에 저장되어있는 content를 client가 요청했을 때는 굳이 아카마이 → Hyundai 서버간의 트래픽은 발생할 필요 없다. 그러면 전체적으로 부하가 줄어든다. Cache서버의 목적이 바로 불필요한 네트워크 트래픽을 줄이기 위함이다. 아카마이라는 회사가 그 서비스를 제공해주는 것이다.


이상으로 HTTP Cache에 대한 설명을 마칠 생각이다. 다음 포스팅에는 HTTP가 어떤 Method가 있는지 응답은 각각 어떤 것을 의미하는 것인지, 그리고 Request/Response에서 각각의 필드는 어떤 의미인지를 알아볼 예정이다.


참고 : 


# How Cache Works

https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#cache-control

http://www.mobify.com/blog/beginners-guide-to-http-cache-headers/


# HTTP CACHE

http://odino.org/don-t-rape-http-if-none-match-the-412-http-status-code/