10장 보안: 브라우저를 보호하는 HTTP의 기능
10.1 기존의 공격
브라우저의 외부인 OS자체에 접근하는 공격이 많았습니다. 기존에는 OS를 파괴하는 것이 목적이였고, 통신내용이나 키를 훔쳐보는 것이 주목적이였습니다. 이들은 더이상 사용되지 않는다는것이 아닙니다.
10.2 브라우저를 노리는 공격의 특징
브라우저의 자체를 노리는 것 뿐만아니라 브라우저가 열람하는 서비스에서 보내는 HTML 및 JS의 취약점도 공격대상이 됩니다.
10.3 크로스 사이트 스크립팅
웹 서비스쪽 프로그램에서 입력된 값을 확인하지 않고, HTML에 그대로 넣어 출력할 경우, 악의적인 스크립트가 실행될 수 있는데 이를 Cross-Site Scripting(XSS)라고 합니다. 예를들어 스크립트가 쿠키에 엑세스해 “로그인 상태”를 갈취한다면, 사용자의 입력정보가 다른 사이트로 전송될 수 있습니다.
서버 측 방어
사용자가 입력한 내용을 그대로 HTML로 출력하지 않도록 새니타이즈(살균 처리)해줍니다. 여기에서 출력은 HTML, 외부 프로세스 실행시의 인수, SQL등이 있습니다.
10.3.1 유출 방지 쿠키의 설정
httpOnly 속성을통해 방어할 수 있습니다.
10.3.2 X-XSS-Protection 헤더
X-XSS-Protection 헤더를 사용하면 HTML의 인라인에서 스크립트 태그를 사용하는 경우등의 수상한 패턴을 감지합니다. 이는 브라우저에서 문제가 없을 수도있으므로 파이어폭스는 지원하지 않습니다. 또한 기존 운영중인 사이트에선 기능 동작을 막아 수정이 필요할 수 있습니다.
X-XSS-Protection: 1; mode=block
Shell
복사
10.3.3 Content-Security-Policy 헤더
Content-Security-Policy 헤더는 웹사이트에서 사용할 수 있는 기능을 세밀하게 ON/OFF를 할 수 있는 기술입니다. 이를 서버에서 설정하여 XSS처럼 JS가 예상치 못한 동작을 막아줍니다. 디렉티브는 열 종류 이상 정의되어 있으며, 크게 4가지로 분류됩니다.
HTML에서 로드하는 각종 리소스 파일의 사용 권한을 설정하는 지시문입니다. 브라우저는 정의된 범위를 넘어선 엑세스를 오류로 처리합니다.
브라우저환경에서는 헤더로 옵트인되지만, 크롬 OS 등에서 사용되는 크롭 앱은 Content-Secruity-Policy 지원이 필수입니다.
리소스 파일의 엑세스 권한을 설정하는 디렉티브
지시문 | 제한대상 |
base-uri | 도큐먼트의 base URI(상대 경로의 시작점) |
child-src | Web Worker, <iframe>으로 이용할 수 있는 URL |
connect-src | XMLHttpReqeust, WebSocket, EventSource와 같이 자바스크립트로 연결할 출처 |
font-src | CSS의 @font-face에서 로드할 웹 글꼴 |
img-src | 이미지와 파비콘을 로드할 출처 |
manifest-src | 매니페스트를 로드할 출처 |
media-src | <audio>와 <video>를 제공하는 출처 |
object-src | 플래시나 자바 애플릿 등 기타 플러그인에 대한 제어 |
script-src | 자바스크립트를 로드할 출처 |
style-src | 읽기 가능한 스타일시트를 로드할 출처 |
세미콜론으로 구분해 각 지시문을 나열하고, 각 항목에는 로드 허가를 나타내는 키워드, 데이터 속성과 URL을 뒤로 배치해 갑니다.
Content-Secruity-Policy: img-src 'self' data: blob: filesystem:; media-src mediastream:; script-src 'self' https://store.example.com
Shell
복사
다음과 같은 값으로 설정할 수 있습니다.
키워드/데이터 속성 | 설명 |
none | 로드를 금지합니다. |
self | 같은 출처를 지정합니다. |
unsafe-inline | 스크립트 및 인라인의 <script> 태그, 이벤트 핸들러의 자바스크립트: 표기, 인라인의 <style>을 허가합니다. 이름 그대로 XSS의 위험이 있습니다. |
unsafe-eval | 문자열을 자바스크립트로서 실행하는 eval(), new Function(), setTimeout()등의 실행을 허가합니다. XSS 위험이 있습니다. |
data: | data URI를 허가합니다. |
mediastream | mediastream:URI 허가합니다. |
blob: | blob:URI를 허가합니다. |
filesystem: | filesystem:URI를 허가합니다. |
mediastream: 데이터 속성은 HTML5 스트리밍을 사용하고, data: 데이터 속성은 BASE64로 인코딩 된 이미지 파일의 문자열을 <image> 태그의 소스로 설정하거나, css 텍스트에서 이미지 데이터를 삽입하여 이미지를 표시할 때 사용합니다.
지시문 | 인수의 종류 | 제한 대상 |
referrer | no-refferer, no-referrer-when-downgrade, origin, origin-when-cross-origin, unsafe-url | 리퍼러의 동작을 변경합니다. |
report -uri | URL | 브라우저에서 위반 사항을 탐지하면, 지정된 서버로 JSON 형식으로 전송합니다. |
reflected-xss | allow, block, filter | 반사형 크로스 사이트 스크립팅으로 불리는 공격에 대한 필터를 활성화합니다. |
Content-Security-Policy는 브라우저가 실시하는 검사로, 오류는 클라이언트 쪽에 표시되지만, 서버 개발자가 그 오류로 정보를 직접 볼 수는 없습니다.
일괄로 보안을 향상시키는 지시문
지시문 | 인수의 종류 |
default-src | 리소스의 액세스 범위 일괄 설정으로 갭려 설정이 우선시됨 |
sandbox | 팝업, 폼 등의 허용설정 |
upgrade-insecure-requests | HTTP 통신을 모두 HTTPS로 변경합니다. |
Content-Security-Policy는 XSS 대책의 강력한 수단이지만, 너무 강하게 설정 시 정상적인 웹사이트 동작이 방해될 수 있습니다. 이대신 Content-Security-Policy-Report-Only 헤더 사용 시 검사는 하지만, 동작은 멈추지 않습니다.
10.3.4 Content-Security-Policy와 자바스크립트 템플릿 엔진
템플릿 엔진들의 일부는 Content-Security-Policy를 사용시 문제가 생기기도합니다.
10.3.5 Mixed Content
현재 대부분 HTTPS지만 광고나 외부 서비스등으로 HTTP가 섞이기도 합니다. 이때 경고가 뜨는데, Content-Security-Policy의 헤더의 upgrade-insecure-requests 지시문을 사용하는 방법이 있습니다.
Content-Security-Policy: upgrade-insecure-requests
Shell
복사
완전히 차단하는 방법도 있습니다.
Content-Security-Policy: block-all-mixed-content
Shell
복사
10.3.6 교차 출처 리소스 공유
오리진 사이에 자원을 공유하는 방법으로 교차 출처 리소스 공유(cross-origin-resource-sharing)입니다. 이는 클라이언트에서 서버로 엑세스하기 직전까지의 권한 확인 프로토콜입니다.
요청에 프리플라이트 요청을 포함한 actual request와 simple cross-origin request 두가지가 있습니다.
simple corss-origin request의 조건은 다음 세가지입니다.
•
HTTP 요청 메서드가 단순 메서드
•
헤더가 모드 심플 헤더(Accept, Accept-Language, Content-Language, Content-Type이외는 제외)
•
Content-Type을 포함하는 경우 그 값이 application/x-www-form-urlencoded, multipart/form-data, text-plain 중 하나
이 조건이 아닐 경우 프리플라이트 요청이 필수이며, 이땐 다음 헤더를 붙어 Options 메서드로 전송합니다.
•
Access-Control-Request-Method 요청 헤더: 통신을 허용하길 원하는 메서드 지정
•
Access-Control-Request-Headers 요청 헤더: 허용하길 원하는 헤더를 쉼표로로 구분해 나열
•
Origin 응답 헤더: 통신 출처 웹 페이지의 도메인 이름을 지정
크로스 오리진 통신은 기본적으로로 쿠키를 송수신하지 않습니다. 클라이언트에서 보내기로 설저한 Fetch, XMLHttpRequest에서 서버가 허가한 경우에만 보냅니다.
•
Access-Control-Allow-Origin 응답 헤더: 통신을 허용할 오리진 이름으로, 쿠키를 이용하지 않을 때는 와일드카드로 모든 도메인을 일괄적으로 허용하기도함
•
Access-Control-Allow-Method 응답 헤더: 대상 URL에 허용되는 메서드 이름. 프리플라이트 요청이 필요없는 간단 메서드는 생략 가능
•
Access-Control-Allow-Headers 응답 헤더: 대상 URL에 허용되는 헤더 이름 목록으로 프리플라이트 요청이 필요없는 간단한 헤더는 생략 가능
•
Access-Conrol-Allow-Credentials 응답 헤더: 쿠키 등의 자격 증명을 서버가 받는 것을 허용할 때 부여되며, 값으로는 true만 설정 가능
•
Access-Conrol-Expose-Headers 응답 헤더: 허용이 아닌 서버에서 반환하는 응답 헤더 중 스크립터에서 참조할 수 있는 헤더이름 목록을 반환
브라우저는 이 정보들을 바탕으로 실제로 보내려는 내용들과 비교해 통신할 수 있는지 판단합니다.
프리플라이트 요청은 요청 전에 매번 전송되지 않고, 캐시를 통해 통신을 생략하는 방법도 포함되어 있습니다.
•
Access-Conrol-Max-Age 응답 헤더: Cache-Control을 사용한 캐시와 마찬가지로 캐시 가능한 초 수를 서버에서 클라이언트로로 전달합니다.
10.4 중간자 공격
중간자 공격(man-in-the-middle attack MITM)은 프록시 서버가 통신을 중계할 때 내용을 빼내 정보가 누설되는 문제입니다. 이를 해결하기 위해선 HTTPS를 이용해야합니다.
10.4.1 HSTS
중간자 공격에 대항하는 HTTP의 기능 중 하나가 RFC 6797에 정의된 HTTP Strict Transport Securty(HSTS)입니다. 이는 서버측에서 앞으로 접속 시 HTTPS로 접속해 달라 전달하는 기능입니다. incluudeSubDomains가 브라우저에 서브 도메인도 대상임을 전달합니다.
Strict-Transport-Security: max-age=31536000;includeSubDomains
Shell
복사
브라우저에는 이 헤더를 보낸 URL의 데이터베이스가 있습니다. 브라우저가 지정된 사이트에 엑세스할 때 자동으로 HTTPS 사이트에 접속하러 갑니다.
단점도 존재하는데 처음 연결 시 HTTP로 통신이 이루어지는데 이때 악의적 프록시가 리다이렉션 URL을 변조 시 피싱사이트로 유도됩니다..
이를 위해 새로운 방호벽이 추가되었는데, 크롬은 처음부터 이 DV를 설정해두려고 정보를 수집합니다.
중간자 공격에는 한가지 맹점이 있는데, 중간자의 인증서가 승인되면 합법적으로 HTTPS 통신의 비밀을 깰 수 있습니다.
10.4.2 HTTP 공개 키 피닝
HTTP 공개 키 피닝(HTTP Public Key Pinning-HPKP)이 RFC 7469에서서 공개되었습니다. 피닝이란 픈으로 고정한다로, 공개 키 목록을 처음 엑세스할 때 받아와 로컬에 핀으로 꼽아 저장합니다. 이후 엑세스할때는 서버가 보낸 인증서의 공개 키와 고정해둔 공개 키를 비교해 사이트 인증서가 무단으로 변경되지 않았는지 확인합니다.
HSTS와 비슷한 생애주기를 따릅니다.
서버 → 공개 키 정보 → 사전에 몇개 웹사이트 인증서에 포함된 공개 키 설치
브라우저는 서버에 처음 엑세스 시 public-key-pins헤더를 받는데 이를 기록해두었다, TLS 통신 전 인증서를 받는 타이밍에 키를 통해 인증서 손상여부 확인
10.5 세션 하이재킹
웹 서비스의 세션 토큰을 훔쳐 웹사이트에 로그인하는 공격입니다.
다음 두 가지 방법을 통해 하이재킹을 피할 수 있습니다.
•
HTTPS 화
•
Set-Cookie: httpOnly, secure
10.5.1 오래된 세션 관리와 세션 고정 공격
오래된 피쳐폰에선 쿠키를 쓸 수 없기때문에 JSESSIONID나 PHPSESSIONIUD라는 이름에 키를 저장했는데, 공격자가 작성한 세션 토큰을 포함하는 URL을 통해 엑세스 하도록해 접속가능하도록 하는 것을 말합니다.
10.5.2 쿠키 인젝션
쿠키의 사양을 역으로 취한 방법으로 HTTPS 연결을 우회할 수 있습니다. HTTPS로 은닉된 도메인의 쿠키에에 대해 다른 하위 도메인으로 덮어쓰거나(sub.example.com), 보다 URL의 상세한 쿠키를 설정해(example.com/some) 원래 HTTPS로 지정된 도메인의 쿠키를 무효화하고 세션 고정화 공격의 발판으로 삼는 것 입니다.
10.6 사이트 간 요청 위조
본인이 의도하지 않은 서버 요청을 관계없는 페이지에 보내도록 조작하는 것을 사이트 간 요청 위조(cross-site request forgery-CSRF)입니다.
10.6.1 CSRF 대책 토큰
CSRF를 방지하는 방법으로는 HTTP 스테이트리스성을 제한하는 방법이 자주 사용됩니다. 폼에 숨겨진 필드에 토큰을 집어 넣고, 서버쪽에서 토큰이 없는 모든 요청을 거절하는 방법등이 있습니다. 단 세션 토큰을 CSRF 대책 토큰으로 사용해서는 안되는데, 쿠키는 httpOnly로 보호할 수 있지만, CSRF 대책토큰은 JS에서 쉽게 접근할 수 있기 때문입니다.
10.6.2 SameSite 특성
쿠키에 SameSite 속성을 부여할 수 있는데, 이는 같은 사이트가 아닌 한 쿠키를 보내지 않도록 하는 겁니다.
10.7 클릭재킹
클릭재킹 사례는 두가지 모두 Iframe을 이용합니다.
•
트위터등 자주사용하는 사이트를 투명하게하여 악의적인 페이지위에 겹치는 방식입니다.
•
자주 사용하는 사이트를 아래에 표시하고 그 위에 투명한 레이어로 악의적인 페이지를 표시해 조작하도록 하는 겁니다.
10.7.1 X-Frame-Options 헤더
•
DENY: 프레임 내에서 사용되는 것을 거부합니다.
•
SAMEORIGINB: 동일한 URL 이외의 프레임 내에서 사용되는 것을 거부합니다.
•
ALLOW-FROM http://example.com: 지정한 URL에서 호출될 때만 프레임 내 표시를 허가합니다.
10.8 리스트형 계정 해킹
같은 이메일과 비밀번호를 돌려쓰는 사용자의 보안은 무효가 된다는 것입니다. 이를 위해 2단계 인증, 하드웨어 토큰등을 사용할 수 있습니다.
10.9 웹 애플리케이션을 위한 보안 가이드 라인
•
X-Frame-Options 헤더
•
Content-Security-Policy 헤더
•
Strict-Transport-Security 헤더
•
Public-Key-Pins 헤더
•
Set-Cookie 헤더
•
CSRF 대책 토큰
•
2단계 토큰
•
지오 IP
•
X-Content-TypeOptions 헤더
•
X-XSS-Protection 헤더
10.10 웹 광고 및 보안
측정 방식에는 2가지가 있습니다.
•
쿠키 기반 측정 도구: 사용자에 대해 고유한 ID가 부여되므로, 클릭하고 3개월 이상의 전환 성과까지 가져올 수 있습니다.
•
핑거 프린트 방식: 단말기의 브라우저 정보, IP 주소 등등 각종 정보를 사용해 사용자를 카테고리화합니다.
10.10.1 서드파티 쿠키
서드파티 쿠키란 광고 등의 용도로 외부 서비스에서 읽을 수 있는 쿠키를 삽입해 사이트를 넘어서 행동 추적을 가능하게 해주는 쿠키입니다.
•
img 태그로 참조된 이미지를 반환할 때 Set-Cookie 헤더를 포함하는 방법
•
태그 iframe으로 폼을 만들어 전송하는 방법
•
팝업 창을 표시하는 방법
•
자바스크립트로 postMessage를 이용해 다른 사이트를 열려있는 윈도우와 정보를 교환하는 방법
10.10.2 쿠키 이외의 대체 수단
클라이언트를 고유하게 식별하는 수단으로 가장 많이 사용되는 방법이 쿠키에 세션 토큰을 기록하는 방법입니다. 이를 좀비 쿠키라고 합니다.
•
HTML5의 각종 스토리지
•
ETag
•
임의로 생성한 이미지
•
기타 플래시나 실버라이트, 자바 애플릿 등의 저장 영역
10.10.3 구글 애널리틱스
사용자 방문 기록을 가져오는 방법인데, JS를 통해 퍼트스파티 쿠키로서 ID 정보를 쿠키에 저장합니다.