HTTP 헤더
HTTP요청/응답을 할 때 HTTP body, HTTP header를 보낸다. 이 중 헤더를 다룬다.
API 기준으로
HTML, XML, JSON 등 본문 : HTTP body
General, Response Headers, Request Headers에 담기는 것들이 헤더이다.
헤더는 콜론(:) 으로 서로 구분되는 key - value 형태로 설정된다. http 요청을 할 때 3가지의 헤더인 일반헤더, 요청헤더, 응답헤더가 자동으로 생기고 서버에서 설정하는 헤더를 응답헤더, 클라이언트에서 설정한 헤더를 요청헤더라고 한다.
HTTP 헤더 자체가 굉장히 유연하게 설계가 되어 있기 떄문에 커스텀하게 만들 수 있지만 보통은 지정되어있는 key값에 value를 담아 헤더를 설정한다. 예를 들어 쿠키를 설정할 때 요청헤더에는 Cookie라는 key에 응답헤더에는 Set-cookie라는 key에 쿠키를 담아 설정한다.
일반헤더
일반헤더에는 요청한 URL, 요청 메서드, 해당 자원을 요청할 때 해당 자원의 출처를 나타내는 URL을 노출시킬지 말지를 정하는 보안정도가 설정되어있는 Refferer Policy 등이 들어간다.
요청헤더
클라이언트가 서버에 요청할 때 클라이언트가 설정하는 또는 자동으로 설정되는 헤더를 뜻한다. 요청헤더에는 메서드, 클라이언트의 OS, 브라우저 정보등이 담긴다.
응답헤더
서버가 클라이언트에게 응답을 보낼 때 설정하는 또는 자동으로 설정되는 헤더를 뜻한다. 응답헤더에는 서버의 소프트웨어 정보 등이 담긴다. 예를 들어 nginx를 프록시서버로 두었다면 해당정보가 표기된다.
하지만 대부분의 서버는 일반적으로 해커가 서버에서 어떤 소프트웨어가 사용되고 있는지 알기 어렵게 하기 위해 서버 정보를 숨긴다.
HTTP/1.0과 HTTP/1.1의 차이
HTTP요청이라는 기술은 1.0부터 시작해 지금은 3까지 많은 발전이 이루어 졌다. 발전과정을 보자.
HTTP/1.0
수명이 짧은 연결이라고 한다. HTTP요청은 자체 요청에서 완료가 된다. HTTP 요청당 TCP 핸드셰이크가 발생되며 기본적으로 한 연결당 하나의 요청을 처리하도록 설계되었다. 한번 연결할 때마다 TCP 연결을 계속 해야하니 RTT가 늘어나는 문제가 있었다.
한 번 요청할 때마다 핸드셰이크가 발생되어 서로 요청, 응답하는 왔다갔다하는 시간이 증가함.
HTTP/1.1
1.0의 단점을 보완한 프로토콜이다. 크게 3가지의 차이가 있다.
- keep-alive default
매번 데이터를 요청할 때마다 TCP 연결을 하는게 아닌 한번 해놓고 계속해서 데이터를 받을 수 있도록 만들었다.
- 호스트 헤더
HTTP/1.0은 서버가 하나의 호스트만 가진다고 가정하기 때문에 HTTP/1.0은 헤더에 호스트를 포함하지 않았다. 그러나 사실 서버는 여러개의 호스트를 가질 수 있으며 이런 유연성을 위해 HTTP/1.1은 헤더에 특정 호스트를 포함할 수 있도록 변경되었으며 항상 호스트를 포함해 요청하도록 바뀌었다.
- 대역폭 최적화
HTTP/1.0의 경우 어떠한 파일을 다운로드 받다가 연결이 끊기면 다시 다운로드 받는 것이 불가능했다. 1.1에서는 이를 다시 다운로드 받을 수 있게 바뀌었다.
예를 들어 1.0에서는 10KB 파일을 다운로드 받는다고 했을 때 5KB까지만 받고 다시 다운로드 받는 것이 불가능했다. 이를 1.1에서는 Range:bytes=5000- 라는 헤더를 추가해 다운로드 재개 요청을 할 수 있게 바뀌었다.
요청을 줄이기 위한 기술(RTT 줄이기)
HTTP/1.1로 발전했음에도 불구하고 각 서버 요청마다 늘어나는 RTT에는 변함이 없었기 때문에 이 요청을 줄이기 위한 여러가지 기술들이 있다.
대표적으로 이미지스프라이트, 코드압축, Base64 인코딩 기술을 같이 쓰게 되었다. 참고로 HTTP 버전이 올라간 뒤에도 이러한 기술들을 같이 쓰곤 한다.
- 이미지 스프라이트
수많은 이미지를 하나의 이미지로 만들어 하나의 이미지만 다운받아놓고 이를 통해 수많은 이미지를 다운받는 듯한 효과를 내는 것을 말한다.
- 코드 압축
코드를 압축해서 서빙한다. ex) 띄어쓰기 등을 압축해 크기를 줄여 RTT를 줄인다.
- 이미지 Base64 인코딩
이미지 파일을 64진법으로 이루어진 문자열로 인코딩해 이미지 서버에 대한 HTTP 요청을 할 필요가 없도록 만드는 것을 말한다. 하지만 Base64 인코딩을 할 경우 파일크기가 37% 더 커지는 단점이 있었다.
HTTP/1.1의 문제
HTTP/1.1은 고질적인 문제가 있었다. 바로 HOL과 무거운 헤더를 가지는 문제이다.
HOL(Head Of Line Blocking)
네트워크에서 같은 큐에 있는 패킷이 그 첫번째 패킷에 의해 지연될 때 발생하는 성능저하현상을 말한다. 예를 들면 먼저 요청한 파일을 다운받는데 속도가 오래걸리면 뒤에 것도 다운받는 속도가 느린 것이다.
HTTP/2
2009년 구글은 HTTP/1.1의 한계를 극복하기 위해 SPDY 프로토콜을 개발했다. 이 후 2015년, SPDY를 기반으로 하는 HTTP/2 프로토콜을 만들었다.
바이너리 포맷 계층
애플리케이션 계층과 전송계층 사이에 바이너리 포맷 계층을 추가한다. HTTP/1.0은 일반 텍스트 메시지를 전송하고 줄바꿈으로 데이터를 나누었다면 HTTP/2.0은 0과 1로 이루어진 바이너리 데이터로 변경되었고 더 작은 메시지가 프레임으로 캡슐화 되어 전송된다.
멀티플렉싱
단일 TCP 연결의 여러 스트림에서 여러 HTTP 요청과 응답을 비동기적으로 보낼수 있다. 이를 통해 HOL을 해결한다.
HTTP/1.1에서는 병렬 요청을 하려면 다중 TCP연결을 통해 하고 일반적으로는 TCP 연결 하나당 병렬 요청은 불가능했다. 이를 HTTP/2.0에서는 리소스를 작은 프레임으로 나누고 각 스트림에 프레임을 전달한다.
각각의 프레임은 스트림ID, 해당 청크의 크기를 나타내는 프렝미이 추가되었기 때문에 작게 나눠 다운로드가 되더라도 응답데이터에서는 올바른 순서로 재조립할 수 있게 된다.
서버푸시
서버가 리소스를 클라이언트에 푸시할 수 있다. 요청된 html파일과 함께 다른 개체를 별도로 보낼 수 있다. 만약 요청한 html에 css가 포함되어 있따면 별도 요청없이 css를 같이 보낼 수 있다.
헤더압축
HTTP/1.1에서는 무거운 헤더가 있었지만 이를 허프만 인코딩 압축 방법 등으로 압축시킨다. 똑같은 서버에서 2개의 이미지를 준다고 했을 때 중복되는 헤더는 제외한 채 보내고 해당 공통 필드로 헤더를 재구성하며 중복되지 않은 헤더값은 허프만 인코딩 압축 방법으로 압축해 전송한다.
우선순위
서버에서 원하는 순서대로 우선순위를 정해 리소스를 전달할 수 있다.
HTTP/3
HTTP/2는 여전히 TCP를 사용하기 때문에 초기 연결에 대한 RTT로 인한 지연시간이 발생한다. 이 시간마저 줄이고 싶었고 이를 해결한 버전이 HTTP/3이다.
QUIC(Quick UDP Internet Connections)라는 계층 위에서 돌아가며, TCP기반이 아닌 UDP 기반으로 돌아가며 HTTP/2에서 장점이었던 멀티플렉싱 등을 가지고 있으며 초기 연결 설정시 지연시간 감소라는 대표적 특성이 있다.
TCP의 경우 3 - RTT가 필요했다면 QUIC는 1 - RTT만 필요하다는 장점이 있다. HTTP/2나 HTTP/3은 HTTPS 위에서 돌아가는데 TLS로 암호화 통신을 구축할 때의 핸드셰이크를 활용한다. 이를 기반으로 1 - RTT만에 연결을 성립할 수 있다.
또한 전송된 패킷이 손실되었다면 수신측에서 에러를 검출하고 수정하는 방식이며 열악한 네트워크 환경에서도 낮은 패킷 손실률을 자랑하는 순방향 오류 수정 메커니즘이라는 특징을 가진다.
암호화
암호화는 승인된 당사자만 정보를 이해할 수 있도록 데이터를 스크램블한 방법이다. 이를 복호화하려면 송신자와 수신자가 서로 동의한 ‘키’가 있어야 한다.
스크램블
각 단어나 문자를 패턴에 따라 암호화하는 것이 아니라 무작위 방식으로 개별 데이터 비트를 섞는 것을 말한다.
대칭 암호화
키를 하나만 사용하는 암호화 방법이다. 예를 들어 “hello”라는 텍스트릴 키로 암호화 한다고 가정하자. 동일한 키로 암호를 해독해서 hello를 반환한 것을 볼 수 있다.
Plaintext + key = hello + 2jd8932kd8 = X5xJCSycg14
Ciphertext + key = X5xJcSycg14 + 2jd8932kd8 = hello
이런 식이다.
비대칭 암호화
비대칭 암호화는 공개키 암호화라고도 부른다. 공개키 암호화는 두 개의 다른 키(공개키, 개인키)로 데이터를 암호화하거나 서명하고 키 중 하나인 공개 키를 누구나 사용할 수 있도록 하는 방법이다. 공개키로 암호화된 데이터는 개인키로만 복호화할 수 있게 한다.
HTTPS를 가능하게 하는 프로토콜인 TLS는 부분적으로 비대칭 암호화를 사용한다. 비대칭 암호화로 인증을 한 후 대칭 암호화로 보안적 통신을 시작한다.
(비대칭 암호화가 보안성은 높을 수 있으나 cost가 비교적 높기 때문에 부분적으로 사용한다.)
TLS 핸드셰이크 과정에서 처음 인증할 때 비대칭 암호화를 하고 그 이후 클라이언트와 서버는 “세션키”라는 키를 기반으로 대칭 암호화를 통한 통신을 한다.
암호화의 필요성
암호화는 의도된 수신자 또는 송신자를 제외하고는 통신을 하이재킹하여 읽을 수 없게 한다. 이를 통해 민감한 데이터의 유출을 방지하고 데이터 무결성을 보장한다.
HTTPS와 TLS(SSL)
HTTP/2나 HTTP/3은 HTTPS 위에서 돌아가는데 TLS로 암호화 통신을 구축할 때의 핸드셰이크를 활용한다. 이를 기반으로 1 - RTT만에 연결을 성립할 수 있다.
HTTPS = HTTP + TLS라고 볼 수 있다.
TLS는 전송 계층에서 보안을 제공하는 프로토콜이다. 클라이언트와 서버가 통신할 때 TLS를 통해 제 3자가 메시지를 도청하거나 변조하지 못하도록 한다.
TLS(SSL) 핸드셰이크
위의 과정이 1 - RTT 즉 한번 왕복으로 이루어지는 과정이다.
- ClientHello
클라이언트는 TLS 버전, 사이퍼슈트와 클라이언트 랜덤값, 임시 DH 매개변수를 서버에게 보낸다.
- ServerHello, EncrypetedExtensions, Certificate, CertificateVerify
서버는 클라이언트로부터 받은 옵션을 확인한다. 서버와 클라이언트 모두에서 지원하는 가장 높은 TLS 버전을 식별하여 결정하고, 사이퍼슈트 지원여부를 확인한다. 공개키가 포함된 SSL 인증서, 서버 랜덤값, 임시 DH 매개변수를 보낸다. 그리고 클라이언트와 서버가 각각 서로 교환한 DH 매개변수를 사용하여 임시 암호키(세션키)를 생성한다.
- Finished
클라이언트와 서버가 세션키를 기반으로 대칭 암호화된 통신이 시작된다.
DH 매개변수
DH는 Diffie-Hellman을 의미한다. Diffie-Hellman 알고리즘은 아래의 과정을 통해 공통의 암호키를 생성한다.
사이퍼슈트
사이퍼슈트는 프로토콜, AEAD 사이퍼 모드, 해싱 알고리즘이 나열된 규약을 말하며 암호제품군이라고도 불린다.
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
- TLS_AES_128_CCM_SHA256
- TLS_AES_128_CCM_8_SHA256
TLS 1.3 버전에는 위와같이 5개가 있다.
예를 들어 TLS_AES_128_GCM_SHA256에는 세가지 규약이 들어있음을 뜻한다.
- TLS = 프로토콜
- AES_128_GCM 은 AEAD 사이퍼모드
- SHA256은 해싱 알고리즘
AEAD 사이퍼모드
AEAD는 데이터 암호화 알고리즘이다. AES_128_GCM을 예로 들면 128비트의 키를 사용하는 표준 블록 암호화 기술과 병렬 계산에 용이한 암호화 알고리즘 GCM이 결합된 알고리즘을 뜻한다.
해싱 알고리즘
해싱 알고리즘은 데이터를 추정하기 힘든 더 작고, 섞여 있는 조각으로 만드는 알고리즘이다. SHA-256 알고리즘을 예로 들면 해시 함수의 결과값이 256비트인 알고리즘이며 비트코인을 비롯한 많은 블록체인 시스템에서도 사용된다.
Q. TLS에서의 해싱 알고리즘 사용?
인증서가 올바른 인증서인지 확인할 때 전자서명을 이용하게 되는데 이 때 해싱 알고리즘이 사용된다.
- 인증 생성작업 : 전자 서명을 만드는데 서명되는 메시지를 해싱한다.
- 인증 확인작업 : 메시지를 복호화해서 해시를 서로 비교해 올바른 메시지인지 확인한다.
전자서명은 송신자가 자신의 신원을 증명하는 절차 또는 정보를 말한다.
예를 들어 네이버에서 다운로드한 프로그램이 악성인지 네이버에서 공식적으로 다운로드한 프로그램인지 확인하려면 어떻게 해야할까?
프로그램 안에 제작자 표시를 할 수 있고, 이 제작자 표시는 우리가 조작이 쉽지 않도록 기술적인 장치를 기반으로 되어있는데 이것이 전자서명이다.
이 전자서명을 통해 인증서에 적힌 주체가 “서비스제공자”인지 확인하고 인증서에 기록된 전자서명을 기반으로 CA의 공개키로 복호화해 지문을 얻고 인증서에 기록된 정보들을 해시함수에 입력하여 해시를 얻어내 두 해시의 일치 여부를 확인한다.
인증서
주체(인증서 발급한 CA, 도메인, 웹사이트 소유자, 인증서 소유자), 공개키를 포함하는 단순한 데이터 파일이다. 보통 인증기관인 CA에서 발급한 SSL 인증서를 기반으로 인증작업을 수행한다.