[HTTP 완벽 가이드] - 9주차

10장 HTTP/2.0

HTTP/2.0의 등장 배경

HTTP/1.1은 커넥션 통해 하나의 요청과 하나의 응답만을 할 수 있어 심각한 회전 지연 문제 발생!

→ 이 문제를 해결하기 위해 병렬 커넥션과 파이프라인 커넥션을 도입되었지만 성능 개선에 대한 근본적인 해결책은 되지 못했다.

이 문제를 해결하기 위해 여러 회사가 각종 프로젝트를 시작하였는데, 최종적으로 구글의 SPDY의 실험적인 프로토콜을 기반으로 HTTP/2.0 프로토콜을 설계함.

개요

HTTP/2.0의 특징

  • 바이너리기반 프로토콜
  • 스트림을 통해서 보내지며 하나의 커넥션 위에 여러 개의 스트림이 동시에 만들어질 수 있다.
  • 서버푸시 도입(클라이언트에게 필요한 리소스를 요청을 받지 않아도 서버측에서 보내주는 것)

HTTP/1.1과의 차이점

프레임

HTTP/2.0에서 모든 메시지는 프레임에 담겨 전송된다.

  • R: 예약된 2비트 필드, 의미가 정해져 있지 않고 반드시 0이어야하며 받는쪽에서 이 값을 무시해야한다.
  • 길이: 페이로드의 길이를 나타내느 14비트 무부호 정수. 이 길이에 프레임 헤더는 포함X
  • 종류: 프레임의 종류
  • 플래그: 8비트 플래그. 플래그 값의 의미는 프레임의 종류에 따라 다르다.
  • R: 예약된 1비트 필드. 첫 번째 R값과 마찬가지
  • 스트림 식별자: 31비트 스트림 식별자. 특별히 0은 커넥션 전체와 연관된 프레임을 의미

HTTP/2.0은 총 10가지 프레임을 정의하고 있고 페이로드의 형식이나 내용은 프레임의 종류에 따라 다르다.

스트림과 멀티 플렉싱

스트림은 HTTP/2.0 커넥션을 통해 클라이언트와 서버 사이에서 교환되는 프레임들의 독립된 양방향 시퀀스

HTTP/2.0의 스트림

  • 하나의 커넥션에서 여러 개의 스트림이 동시에 열릴 수 있다.
  • 우선순위를 가질 수 있다.
  • 한번 사용된 스트림 식별자는 다시 사용할 수 없다.

HTTP/2.0은 WINDOW_UPDATE 라는 프레임을 이용한 흐름 제어를 통해 스트림들이 서로 간섭해서 망가지는 것을 막아준다.

헤더 압축

HTTP/1.0에서는 아무런 압축 없이 그대로 전송되어 이 크기가 영향을 끼침

→ 이를 개선하기 위해 HTTP/2.0에서는 HTTP 메시지의 헤더를 압축하여 전송하며 받는 쪽에서 헤더블록 조각들을 이은 뒤 압축을 풀어 사용한다.

HPACK을 사용하여 헤더를 압축하는데 ‘압축 콘텍스트'를 사용하며, 오동작 하지 않으려면 헤더를 쓰지 않고 버리는 경우에도 반드시 압축 해제를 수행해야 한다.

서버 푸시

서버가 하나의 요청에 대해 응답으로 여러 개의 리소스를 보낼 수 있도록 해준다.

HTML 파일 요청 시, CSS, 이미지, JS 파일등을 서버가 클라이언트로 푸시하는 것.

주의사항

  • 중간의 프락시가 서버 푸시를 막을 수도 있고 반대로, 추가 리소스를 요청하지 않았음에도 전달할 수도 있다.
  • 서버는 오직 안전하고, 캐시 가능하고, 본문을 포함하지 않은 요청에 대해서만 푸시할 수 있다.
  • 푸시할 리소스는 클라이언트가 명시적으로 보낸 요청과 연관된 것이어야 한다. (서버가 보내는 PUSH_PROMISE 프레임은 원 요청을 위해 만들어진 스트림을 통해 보내짐)
  • 클라이언트는 반드시 서버가 푸시한 리소스를 동일 출처 정책에 따라 검사해야 한다.
  • 서버 푸시를 끄고 싶다면, SETTINGS_ENABLE_PUSH 설정을 0으로 설정하면 된다.

알려진 보안 이슈

중개자 캡슐화 공격(Intermediary Encapsulation Attacks)

HTTP/2.0 메시지를 중간의 프락시가 HTTP/1.1 메시지로 변환할 때 메시지의 의미가 변질될 가능성이 있다.

HTTP/2.0은 바이너리 인코딩을 하기 때문에 헤더 필드로 어떤 문자열이든 사용할 수 있게 해주어 위조된 HTTP/1.1 메시지로 번역되는 것을 유발!

긴 커넥션 유지로 인한 개인정보 누출 우려

사용자가 요청을 보낼 때, 회전 지연을 줄이기 위해 클라이언트와 서버 사이의 커넥션을 오래 유지하는 것을 염두에 두고 있다.

이는 개인 정보의 유출에 악용될 가능성이 있다.(브라우저 사용시, 사용자가 무엇을 했는지 알아낼 가능성이 있기 때문)

11장 클라이언트 식별과 쿠키

서버는 서로 다른 수천 개의 클라이언트와 동시에 통신한다. 이 장에서는 서버가 통신하는 대상을 식별하는 데 사용하는 기술을 알아본다.

개별 접촉

HTTP는 익명으로 사용하며 상태가 없다.

연결 자체에 대한 정보를 가지지 않으며 매 요청은 일회성이고 독립적으로 처리됨. → HTTP는 상태가 없다고 하거나 무상태라고 부른다.

현대의 웹 사이트는 이러한 한계를 극복하고 개인화된 서비스를 제공하기 위해 사용자 정보 추적을 시도한다.

  • 개별 인사 - 사용자에게 특화된 환영 메시지나 페이지 내용을 만듦
  • 사용자 맞춤 추천 - 고객의 흥미에 따른 제품 추천
  • 저장된 사용자 정보 - 데이터베이스에 정보들을 저장하여 다음에 입력할 때 사용자 정보를 가져와 편리하게 해줌
  • 세션 추적 - 사용자의 상태를 남김으로써 사용자와 상호작용

사용자 식별을 위한 기술들

  • 사용자 식별관련 정보 HTTP 헤더들
  • 클라이언트 IP 주소 추적으로 알아낸 IP 주소로 사용자 식별
  • 사용자 로그인 인증을 통한 사용자 식별
  • URL에 식별자를 포함하는 기술인 뚱뚱한 URL
  • 식별 정보를 지속해서 유지하는 강력하면서도 효율적인 기술인 쿠키

위 기술들에 대한 내용들을 하나하나 알아볼 것이다.

HTTP 헤더

사용자 정보를 전달하는 가장 일반적인 7가지 HTTP 요청 헤더

헤더 이름헤더 타입설명
From요청사용자의 이메일 주소
User-Agent요청사용자의 브라우저(브라우저 이름, 버전 정보, 운영체제에 대한 정보까지)
Referer요청사용자가 현재 링크를 타고 온 근원 페이지
Authorization요청사용자 이름과 비밀번호(뒤에서 다룸)
Client-ip확장(요청)클라이언트 IP 주소(뒤에서 다룸)
X-Forwarded-For확장(요청)클라이언트 IP 주소(뒤에서 다룸)
Cookie확장(요청)서버가 생성한 ID 라벨(뒤에서 다룸)

클라이언트 IP 주소

초기에는 사용자 식별에 클라이언트 IP 주소를 사용하려고 했지만 이 방법은 다음과 같은 약점을 가진다.

  • 클라이언트 IP 주소는 사용자가 아닌, 사용하는 컴퓨터를 가리킨다.
  • 많은 인터넷 서비스 제공자(ISP)는 사용자가 로그인하면 동적으로 IP 주소를 할당한다.
  • 보안을 강화하고 부족한 주소들을 관리하려고 많은 사용자가 네트워크 주소 변환 방화벽을 통해 인터넷을 사용한다.
  • 보통 HTTP 프락시와 게이트웨이는 원 서버에 새로운 TCP 연결을 한다. 즉 프락시 서버의 IP 주소를 보게 되는데 원본 IP 주소를 보존하려고 Client-ipX-Forwarded-For HTTP와 같은 확장 헤더를 추가하여 문제를 해결하려고 함.

사용자 로그인

사용자 이름과 비밀번호로 인증할 것을 요구해서 사용자에게 명시적으로 식별 요청을 할 수 있다.

HTTP는 WWW-AuthenticateAuthorization 헤더를 사용해 웹 사이트에 사용자 이름을 전달하는 자체적인 체계를 가지고 있다. 더 자세한 내용은 12장에서

이를 사용하는 예시로 사이트에 한 번 로그인하면 브라우저는 요청마다 해당 사용자의 식별정보 토큰을 Authorization 헤더에 담아 서버로 전송하여 세션 진행동안 사용자에 대한 식별을 유지함.

뚱뚱한 URL

사용자의 상태 정보를 포함하고 있는 URL을 뚱뚱한 URL이라고 한다. 그러나 이 기술에는 심각한 문제가 있다.

  • 못생긴 URL - 사용자들에게 혼란을 줌
  • 공유하지 못하는 URL - 특정 사용자와 세션에 대한 상태 정보를 포함한다.
  • 캐시를 사용할 수 없음 - URL로 만드는 것은 URL이 달라지기 때문에 기존 캐시에 접근 X
  • 서버 부하 가중 - 이 URL에 해당하는 HTML 페이지를 다시 그려야함
  • 이탈 - 다른 사이트로 이동하거나 특정 URL을 요청해서 의도치 않게 뚱뚱한 URL 세션에서 ‘이탈'하기 쉽다. 만약 이탈하면 지금까지의 진척사항들이 초기화되고 처음부터 다시 시작해야된다.
  • 세션 간 지속성의 부재 - 뚱뚱한 URL을 북마킹하지 않는 이상 로그아웃하면 모든 정보를 잃음

쿠키

사용자를 식별하고 세션을 유지하는 방식 중에서 현재까지 가장 널리 사용하는 방식

쿠키의 타입

  • 세션 쿠키 - 사용자가 사이트 탐색 시, 관련한 설정과 선호 사항들을 저장하는 임시 쿠키. 브라우저 닫으면 삭제
  • 지속 쿠키 - 삭제되지 않고 더 길게 유지. 디스크에 저장되어, 브라우저를 닫거나 컴퓨터를 재시작하더라도 남아있다.

둘이 다른 것은 파기되는 시점뿐이며 Discard 파라미터가 설정되어 있거나, Expires혹은 Max-Age 파라미터가 없으면 세션 쿠키가 된다.

쿠키는 어떻게 동작하는가

사용자가 처음에 웹 사이트에 방문하면 서버는 클라이언트를 식별하기 위한 유일한 값을 쿠키에 할당한다. 쿠키는 임의의 이름=값 형태의 리스트를 가진다. 이러한 리스트는 Set-Cookie혹은 Set-Cookie2 같은 HTTP 응답 헤더에 기술되어 사용자에게 전달한다.

이 정보를 브라우저가 브라우저 쿠키 데이터베이스에 가지고 있다가 나중에 같은 사이트를 방문하면 이 쿠키를 요청 헤더에 기술해 전송한다.

쿠키 상자: 클라이언트 측 상태

브라우저는 쿠키 정보를 저장할 책임이 있고, 이 시스템을 ‘클라이언트 측 상태’라고 한다. 쿠키 명세에서 이것의 공식적인 이름은 ‘HTTP 상태 관리 체계' 이다.

각 브라우저마다 쿠키를 관리하는 방식이 다르다.

  • 크롬: SQLite파일에 쿠키 저장
  • IE: 캐시 디렉터리에 각각의 개별 파일로 쿠키 저장

사이트마다 각기 다른 쿠키들

브라우저는 수백 수천 개의 쿠키를 가지고 있을 수 있지만 아래의 이유로 몇몇의 쿠키만 보낸다.

  • 쿠키를 모두 전달하면 성능이 크게 저하된다.
  • 쿠키는 서버에 특화된 이름/값 쌍을 포함하기 때문에 대부분 사이트에서는 인식하지 않는 무의미한 값이다.
  • 모든 사이트에 쿠키 전체를 전달하는 것은 잠재적인 개인정보 문제를 일으킬 것이다.

보통 브라우저는 쿠키를 생성한 서버에게만 쿠키에 담긴 정보를 전달한다.

쿠키 Domain 속성

서버에서 쿠키 생성 시, Domain 속성을 기술해서 어떤 사이트가 그 쿠키를 읽을 수 있을지 제어할 수 있다.

쿠키 Path 속성

웹 사이트 일부에만 쿠키를 적용할 수도 있다. → path 속성을 기술하여 해당 경로에 속하는 페이지만 쿠키 전달

쿠키 구성요소

  • Version 0 쿠키(넷스케이프 쿠키)
  • Version 1 쿠키(Version 0 쿠키의 확장으로 널리 쓰이지는 않음)

Version 0 쿠키

Set-Cookie 응답 헤더와 Cookie 요청 헤더와 쿠키를 조작하는 데 필요한 필드들 정의

이 Set-Cookie에 포함되는 속성들

  • 이름 = 값
  • Expires
  • Domain
  • Path
  • Secure

Version 1 쿠키

원 버전인 넷스케이프 표준보다 좀 더 복잡하다. 추가된 주요 변경 사항은 다음과 같다.

  • 쿠키마다 그 목적을 설명하는 설명문이 있다.
  • 브라우저가 닫히면 쿠키를 강제로 삭제할 수 있다.
  • 절대 날짜 값 대신 상대 값으로 쿠키의 생명주기를 결정할 수 있는 Max-Age
  • 도메인과 경로뿐만 아니라 URL의 포트번호로도 쿠키를 제어할 수 있다.
  • 도메인, 포트, 경로 필터가 있으면 Cookie 헤더에 담겨 되돌려 보낸다.
  • 호환되는 버전 번호.
  • 사용자 이름과 추가적인 키워드를 구별하기 위해 Cookie 헤더에 $ 접두어가 있다.

Set-Cookie2헤더에 여러가지 속성들이 있는데 이는 RFC 2965 참조

Cookie 헤더의 추가 정보로 현재 사이트에 들어맞는 필터를 기술할 수 있다.

쿠키와 세션 추적

쿠키는 웹 사이트에 수차례 트랜잭션을 만들어내는 사용자를 추적하는 데 사용한다.

예시: Amazon.com에 방문시 일어나는 트랜잭션의 연속 → 책 참조

쿠키와 캐싱

쿠키 트랜잭션과 관련된 문서를 캐싱하게 되면, 다른 사용자에게 쿠키가 할당돼 버리거나, 개인정보 노출과 같은 최악의 상황이 일어나기 때문에 주의해야한다.

캐시를 다루는 원칙

  • 캐시되지 말아야 할 문서가 있다면 표시하라 → Cache-Control: no-cache=’Set-Cookie’
  • Set-Cookie 헤더를 캐시 하는 것에 유의하라 → 같은 Set-Cookie헤더를 여러 사용자에게 보내면, 사용자 추적에 실패할 것이기 때문
  • Cookie 헤더를 가지고 있는 요청을 주의하라 → 결과 콘텐츠가 개인정보를 담고 있을 수 있기 때문

쿠키, 보안 그리고 개인정보

쿠키의 보안적인 측면에서 우려를 표하는 사람들이 많다. 그러나 제공하는 개인정보를 누가 받는지 명확히 알고 사이트의 개인정보 정책에 유의한다면, 쿠키에 관련한 위험성보다 세션 조작이나 트랜잭션상의 편리함이 더 크다!

12장 기본 인증

웹의 모든 정보가 공용은 아니기에 허가된 사람만이 데이터에 접근할 수 있어야 한다. 그러기 위해서는 서버가 사용자가 누구인지 식별할 수 있어야 하는데, 이 장에서는 HTTP 인증과 이것의 기본이 되는 기본 인증을 알아볼 것이다.

인증

인증은 사용자가 누구인지 증명하는 것이다.

HTTP의 인증요구/응답 프레임워크

요청(클라이언트) ----- 인터넷 ------> 서버       나에게 판매 예측 정보를 보내주세요.

인증요구(클라이언트) <----- 인터넷 ----- 서버     당신은 비밀 재정 문서를 요청했습니다. 사용자 이름과 비밀번호를 보내주세요.

⬇️(사용자에게 비밀번호를 물어본다.)

인가(클라이언트) ------ 인터넷 --------> 서버    나에게 판매 예측 정보를 주세요. 여기에 사용자 이름과 비밀번호가 있습니다.

성공(클라이언트) <----- 인터넷 --------- 서버    좋습니다.당신은 접근 권한을 획득했습니다. 여기 문서를 보냅니다.

인증 프로토콜과 헤더

HTTP는 필요에 따라 고쳐 쓸 수 있는 제어 헤더를 통해, 다른 인증 프로토콜에 맞추어 확장할 수 있는 프레임워크를 제공한다.

프로토콜의 종류

  • 기본인증
  • 다이제스트 인증

이 장에서는 기본인증에 대해서만 설명

단계헤더설명메서드/상태
요청첫 번째 요청에는 인증 정보가 없다.GET
인증요구WWW-Authenticate서버는 사용자에게 사용자 이름과 비밀번호를 제공하라는 지시의 의미401 Unauthorized
인증Authorization클라이언트는 요청을 다시 보내는데, 인증 알고리즘과 사용자 이름과 비밀번호를 기술한 Authorization 헤더를 함께 보낸다.GET
성공Authentication-Info인증 정보가 정확하면, 서버는 문서와 함께 응답한다.200 OK

보안 영역

HTTP가 각 리소스마다 다른 접근 조건을 다루기 위해 기밀 문서를 보안 영역(realm) 그룹으로 나눈다. 보안 영역은 저마다 다른 사용자 권한을 요구한다.

기본 인증

기본 인증은 가장 잘 알려진 HTTP 인증 규약으로, 인증 절차에 대한 내용은 인증 프로토콜 헤더에서 본 내용과 같다.

Base-64 사용자 이름/비밀번호 인코딩

Base-64 인코딩은 바이너리, 텍스트, 국제 문자 데이터(어떤 시스템에서는 문제를 일으킬 수 있는) 문자열 받아서 전송할 수 있게, 그 문자열을 전송 가능한 문자인 알파벳으로 변환하기 위해 발명되었다.

이를 활용하여 사용자 이름과 비밀번호가 노출되는 문제를 예방하는 데 도움을 줄 수 있다.

프락시 인증

중개 프락시 서버를 통해 인증할 수도 있다. 이를 사용하면 프락시 서버에서 접근 정책을 중앙 관리할 수 있어서 통합적인 접근 제어를 하는데 도움이 된다.

프락시 인증과 웹 서버 인증에서 쓰이는 상태코드와 헤더들의 대조표

웹 서버프락시 서버
비인증 상태 코드 : 401비인증 상태 코드: 407
WWW-AuthenticateProxy-Authenticate
AuthorizationProxy-Authorization
Authentication-InfoProxy-Authentication-Info

기본 인증의 보안 결함

보안결함 종류

  • base-64 인코딩을 하여도 디코딩을 할 수 있기 때문에 ‘비밀번호를 그대로' 보내는 것과 다름 없다. → HTTP 트랜잭션을 SSL 암호화 채널을 통해 보내는 방식으로 사용하는 것이 좋다.
  • 보안 비밀번호가 디코딩하기에 더 복잡한 방식으로 인코딩 되어있다고 하더라도 제 3자가 그 이름과 비밀번호를 캡처한 다음 그대로 원 서버에 보내서 인증에 성공하고 서버에 접근할 수 있다.
  • 기본 인증이 치명적이지 않은 앱에서 사용된다 하더라도 그 인증을 다른 여러 사이트(은행과 같은 중요 사이트)에 사용할 수 있기 때문에 굉장히 위험하다.
  • 메시지의 인증 헤더를 건드리지는 않지만, 그 외 다른 부분을 수정해서 개입하는 경우, 기본 인증은 정상적인 동작을 보장하지 않는다.
  • 기본 인증은 가짜 서버의 위장에 취약하다.

기본 인증은 일반적인 환경에서 개인화나 접근을 제어하는데 편리하며, 다른 사람들이 보지 않기를 원하기는 하지만, 보더라도 치명적이지 않은 경우 여전히 유용하다.

기본 인증은 호기심 많은 사용자가 우연이나 사고로 정보에 접근해서 보는 것을 예방하는데 사용한다.

좋은 웹페이지 즐겨찾기