CDN – Cache Poisoning

문제점

CDN 서버를 운영 중에 요청 헤더를 응답 헤더에 포함시키는 오리진이 존재 했습니다. 이 경우 발생할 수 있는 문제점은 Content-Disposition ‘attachment; filename=”hack.exe”와 같은 헤더를 요청 헤더에 포함 했을 때입니다. 일반적인 웹 구성이라면 상관이 없지만 해당 컨텐츠를 캐싱하는 경우 다음과 같이 해당 응답 헤더를 캐싱 해서 문제가 됩니다.

해당 컨텐츠를 브라우저를 통해서 접근하면, 다음과 같이 파일이 받아집니다. 신뢰성 있는 사이트에 올라간 컨텐츠가 받아지면 사용자는 아무 의심없이 실행을 누를 수 있습니다.

공격자는 앞선 예시와 같이 CDN 서버가 캐싱 할 때 일부 헤더 정보를 같이 캐싱하게 해서 임의로 주입한 헤더를 통해 사용자가 공격 받는 상황을 만듭니다.


개념

Content-Disposition

Content-Disposition 헤더는 브라우저에서 해당 컨텐츠를 어떻게 표시할지 알려주는 헤더입니다. 해당 페이지의 일부로 포함(inline) 될 지 아니면 다운로드(attachment) 할 지 결정합니다. 이 글에서는 body에 대한 응답 헤더만을 다루도록 하겠습니다. default는 inline이고 페이지의 일부로 포함되게 됩니다. attachment일 경우 파일이 다운로드 되면 filename이 지정되어 있다면 해당 filename으로 저장이 됩니다.

Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"

mozilla docs: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition

proxy_hide_header

프록시로 사용 되는 서버가 백엔드 서버로 부터 데이터를 받을 때, 프록시에서 특정 헤더를 제외할 필요가 있을 때 사용하는 디렉티브입니다.

Syntax:	proxy_hide_header field;
Default:	—
Context:	http, server, location

Nginx docs: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header


해결책

결론부터 말씀드리면, origin에서 Content-Disposition을 응답 헤더에 의도하고 부착 했는지 아니면 공격자가 부착 했는지를 CDN 운영자가 판단할 수 없기 때문에, 완벽한 해결 방법을 제시 하기는 어렵습니다. 그러나 Content-Disposition: attachment과 관련된 컨텐츠를 사전에 공지 했을 시, 해당 컨텐츠 관련 URI 경로를 따로 두어서 관리할 경우 해당 문제점을 해소할 수 있습니다.

Nginx + Trafficserver 구성에서 URI를 따로 관리하게 될 경우, 다음과 같이 proxy_hide_header와 add_header를 통해서 공격 대상이 될 수 있는 캐싱된 컨텐츠의 헤더를 강제적으로 변경할 수 있습니다.

location /inline {
   proxy_hide_header Content-Disposition;
   add_header Content-Disposition 'inline';
   proxy_pass http://origin;
}
location /attachment {
   proxy_hide_header Content-Disposition;
   add_header Content-Disposition 'attachment';
   proxy_pass http://origin;
}

proxy_hide_header 없이 add_header만 사용할 경우에는 응답헤더에 두개의 Content-Disposition이 나타나게 되서 결과를 예측하기 어렵게 됩니다.

add_header를 부착하지 않을 경우에는 테스트 결과에서는 default인 inline 값이 적용되어 브라우저에 포함되어 나타났습니다.


결과

오리진에서 요청 헤더에 대한 값을 응답 헤더에 포함시키는 것은 공격에 노출되기 쉽기 때문에 지양해야 되며, 사용 하더라도 예외처리 로직을 심을 필요가 있습니다. 해결책으로 사용된 proxy_hide_header 디렉티브는 응용될 곳이 많다고 생각되어 숙지하면 큰 도움이 될 것 같습니다.

Post Author: Jinn