-
[Network] HTTP Network and HTTPSComputer Science 2021. 12. 7. 20:50
HTTP message header
HTTP에서 리퀘스트와 리스폰스가 발생할 때 반드시 메시지 헤더가 포함되어 있는데, 메시지 헤더에는 클라이언트나 서버가 리퀘스트나 리스폰스를 처리하기 위한 정보를 담고 있습니다.
그래서 HTTP Header Field는 무엇이에요?
HTTP 헤더 필드는 HTTP 메시지를 구성하는 요소 중 하나 입니다. 클라이언트와 서버간의 통신에서 리스폰스 리퀘스트 모두에 사용되고, 부가적인 중요한 정보를 담고 있습니다. 예를 들어 메시지 바디의 크기나, 사용하는 언어와 인증 정보등을 담고 있습니다. 흔히 http documents를 작성할 때 우리는 메타태그와 lang정보등이 <head> 부분에 담겨있는 것을 확인할 수 있죠.
개발자 도구에서 본 HTTP header의 모습 HTTP 헤더 필드가 중복되면 어떻게 될까?
HTTP 헤더 필드 중 같은 이름의 헤더가 2개가 중복되는 경우 브라우저마다 처리 방식이 조금씩 다르지만 보통 선행의 헤더먼저 처리가 되거나 마지막 헤더가 먼저 처리가 됩니다.
HTTP/1.1 이외의 헤더 필드
HTTP 헤더 필드가 RFC2616에서 정의된 47종류만 있는 것은 아닙니다. 쿠키와 set-cookie, Content-Disposition와 같이 비표준 헤더 필드는 RFC4229 HTTP Header Field Registration에 정의되어 있습니다.
End-to-end, Hop-by-hop 헤더
HTTP 헤더는 캐시와 비캐시 프록시 동작을 정의하기 위해 두 가지 카테고리로 분류되어 있습니다.
종단간 헤더(End-to-end Header)
이 카테고리에 분류된 헤더는 리퀘스트라 리스폰스의 최종 수신자에게 전송됩니다. 캐시에서 구축된 리스폰스 중 보존되어야 하고, 다시 전송되면 안되도록 되어 있습니다.
중간 프록시 서버는 종단간 헤더(End-to-end Header)를 수정되지 않는 상태로 재전송해야하며, 캐시는 반드시 이를 저장해야 합니다.
홉간 헤더(hop-by-hop Header)
이러한 헤더는 단일 전송-레벨 연결에서만 의미가 있으며 프록시에 의해 재전송되거나 캐시되어선 안됩니다. 이러한 헤더들은 다음과 같습니다.
- Connection
- Keep-Alive
- Proxy-Authenticate
- Proxy-Authorization
- TE
- Trailer
- Transfer-Encoding
- Upgrade
홉간 헤더는 Connection일반 헤더를 사용해 설정될 수 있음에 유의해야 합니다.
HTTP/1.1 General header field
Cache-Control
Cache-control은 디렉티브로 불리는 명령을 이용해서 캐싱 동작을 지정합니다.
지정된 디렉티브는 파라미터가 있는 것도 있고, 없는 것도 있으며, 다중의 디렉티브가 사용될 때에는 콤마로 구분합니다. 캐쉬 컨트롤의 헤더필드는 리스폰스, 리퀘스트에서 둘 다 사용됩니다.
캐시 리퀘스트 디렉티브 캐시 리스폰스 디렉티브 각 디렉티브에 대한 정보는 https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Cache-Control 에서 확인할 수 있습니다.
Connection
Connection 헤더 필드는 다음의 두 가지 역할을 합니다.
- 프록시에 더 이상 전송되지 않는 헤더필드를 지정
- 지속적 접속 관리
프록시에 더 이상 전송되지 않는 헤더필드를 지정
리퀘스트 혹은 리스폰스에서 Connection 헤더 필드를 사용하며, 프록시 서버에 더 이상 전송하지 않는 헤더필드 (hop-by-hop 헤더) 를 지정할 수 있습니다.
지속적 접속 관리
HTTP/1.1에서는 지속적 접속이 Default 로 되어 있습니다. 따라서 리퀘스트를 송신했던 클라이언트는 접속이 계속 유지 되면서 추가 리퀘스트를 보낼 수 있습니다. 만약 서버에서 명시적으로 연결을 끊는다면 Connection 헤디 필드를 close로 지정해야 합니다.
Connection: close
HTTP/1.1 이전 버전의 HTTP는 지속적 접속이 Default 가 아니었습니다. 그렇기 때문에 오래된 버전의 HTTP에서 지속적 접속을 하는 경우에는 Keep-Alive를 지정해야 합니다.
Connection: Keep-Alive
Pragma
HTTP/1.0과의 후방 호환성을 위해 존재하는 헤더입니다. 지정할 수 있는 형식은 한 개밖에 없습니다.
Pragma: no-cache
이 것은 클라이언트의 Request에서 밖에 사용되지 않습니다. 중간 서버에게 알리기 위해 사용되는데 클라이언트에서 중간 서버의 HTTP 버전을 전부 확인하고 보내는 일은 없기 때문에 보통 Cache-control: no-cache와 함께 보내게 됩니다.
Upgrade
Upgrade 헤더 필드는 HTTP 및 다른 프로토콜의 새로운 버전이 통신에 이용될 때 사용됩니다. 지정한 대상이 전혀 다른 통신 프로토콜이라도 상관이 없습니다.
Upgrade 헤더 필드가 달린 리퀘스트에 대해서 서버는 상태코드 101이라는 리스폰스로 응답할 수 있습니다.
Via
Via 헤더 필드는 리퀘스트 혹은 리스폰스간의 메시지의 경로를 알기 위해 사용됩니다. 프록시 혹은 게이트웨이는 Via 헤더 필드에 자신의 정보를 담아서 보내게 됩니다. 이 헤더 필드는 리퀘스트의 루프 회피, 메시지 추적등에 사용되기 때문에 반드시 부가할 필요가 있습니다.
두 개 이상의 프록시 서버를 지날 때 전에 지난 Via 헤더 필드 위에 또 부가해도 상관 없습니다. 이 헤더는 배송 경로를 알기 위해 TRACE 메소드와 연계해서 자주 사용됩니다.
Warning
기본적으로 캐시에 관한 경고를 유저에게 전달하는 헤더이지만 곧 지원이 중단 될 예정입니다.
HTTP/1.1 Request header field
리퀘스트 헤더 필드는 클라이언트에서 서버로 송신된 리퀘스트에 대한 부가정보와 클라이언트에 대한 정보 및 리스폰스의 콘텐츠에 관한 우선 순위등을 부가합니다.
Accept
Accept 헤더 필드는 유저 에이전트에 처리할 수 있는 미디어 타입과 미디어 타입의 상대적인 우선순위를 전달하기 위해 사용됩니다. 미디어 타입은 타입/서브타입으로 한번에 설정될 수 있습니다.
Accept-charset
Accept-charset은 문자셋의 상대적인 우선 순위를 부가하기 위해 사용됩니다. 문자셋은 한 번에 여러개를 지정할 수 있습니다. 이 헤더필드는 서버 구동형 네고시에이션에 사용됩니다.
💡 컨텐츠 타협 : 브라우저와 서버가 타협을 해서 사용자에게 가장 알맞은 페이지를 주는 것을 말한다. 제공하는 리소스 언어와 문자셋, 인코딩 방식 등을 기준으로 판단한다. 이 것은 3가지 방식이 존재한다.
- 서버 구동형 네고시에이션은 서버에서 판단한다.
- 에이전트 구동형 네고시에이션은 클라이언트에서 판단한다.
- 트랜스페어런트 네고시에이션은 서버와 클라이언트가 각각 판단한다.
Accept-encoding
유저 에이전트가 처리할 수 있는 콘텐츠 코딩과 우선순위를 부가하고 역시 한 번에 여러개를 지정할 수 있습니다.
콘텐츠 코딩에는 다음과 같은 것들이 있습니다.
- gzip : 파일 압축 프로그램에서 생선된 인코딩 포맷(RFC1952)으로 Lempel-Ziv 부호(LZ77)와 32비트 CRC를 사용합니다.
- compress : UNIX 파일 압축 프로그램에 의해서 만들어진 인코딩 포맷으로 Lemple-Ziv-Welch 부호(LZW)를 사용합니다.
- deflate : Zlib 포맷(RFC1950)과 deflate 압축 알고리즘(RFC1951)에 의해서 만들어진 인코딩 포맷을 조합한 것 입니다.
- identity : 압축과 변형을 하지 않는 디폴트 인코딩 포맷입니다.
"*"를 지정하면 와일드 카드로서 모든 인코딩 포맷을 가르킵니다.
Authorization
Authrization 헤더 필드는 유저 에이전트 인증 정보 (크리덴셜 값)을 전달하기 위해서 사용됩니다. 통상, 서버에서 인증을 받으려 하는 유저 에이전트는 상태 코드 401 리스폰스의 뒤에 리퀘스트에 Authorization 헤더 필드를 포함합니다. 공유 캐시가 Authrization 헤더 필드를 포함하는 리퀘스트를 받은 경우는 조금 다른 동작을 합니다. RFC2616에 자세한 정보가 있습니다.
Except
이 헤더 필드는 클라이언트가 서버에 특정 동작 요구를 전달합니다. 기대하고 있는 요구에 서버가 응답하지 못해서 에러가 발생하는 경우에는 상태 코드 417 Expectation Failed 를 반환합니다. 클라이언트는 이 헤더 필드에 원하는 확장을 딸려 보낼 수 있지만 HTTP/1.1의 사양에서는 100-Continue만 정의되어 있습니다. 상태 코드 100 리스폰스를 가진 클라이언트는 리퀘스트를 할 때 Except: 100-Continue 로 지정해야 합니다.
Host
가상 호스트는 동일 IP로 운용되기 때문에 Host헤더 필드로 구별됩니다. 이 헤더 필드는 리퀘스트한 리소스의 인터넷 호스트와 포트 번호를 전달합니다. Host 헤더 필드는 HTTP/1.1에서 유일한 필수 헤더 필드입니다. Host 헤더 필드가 존재하는 이유는 1대의 서버에서 복수의 도메인을 할당할 수 있는 가상 호스트의 구조와 매우 깊은 관련이 있습니다.
리퀘스트가 서버에 오면 호스트 명을 IP 주소로 해결해 리퀘스트가 처리됩니다. 이 때 같은 IP 주소로 복수의 도메인이 적용되어 있다고 한다면 어느 도메인에 대한 리퀘스트인지 알 수가 없습니다. 그래서 Host 헤더 필드에 리퀘스트를 받을 호스트명을 명확하게 해야 할 필요가 있고 따라서 필수 헤더 필드 입니다. 만약 서버에 호스트 명이 설정되어 있지 않은 경우에는 값을 비워서 보냅니다.
조건부 리퀘스트들
If-Match
if-xxx 라는 서식의 리퀘스트 헤더 필드는 조건부 리퀘스트라고 부릅니다. 조건부 리퀘스트를 받은 서버는 지정된 조건에 맞는 경우에만 리퀘스트를 받습니다.
이 헤더 필드는 조건부 리퀘스트의 하나로 서버 상의 리소스를 특정하기 위해서 엔티티 태그(Etag) 값을 전달합니다. 이 때 서버는 약한 ETag 값을 사용할 수 없습니다.
서버는 If-Match의 필드 값과 리소스의 ETag값이 일치한 경우에만 리퀘스트를 받아들일 수 있습니다. 일치하지 않으면 상태 코드 412 Precondition Failed 리스폰스를 반환합니다.
If-Modified-Since
이 헤더 필드는 조건부 리퀘스트의 하나로 리소스가 갱신 날짜가 필드 값보다 새롭지 않다면 리퀘스트를 받아들이겠다는 뜻 입니다. 필드 값에 저장된 날짜 이후에, 지정한 리소스가 갱신되어 있지 않는 경우 304 Not modified 를 반환합니다.
If-None-Match
이 헤더 필드는 조건부 리퀘스트의 하나로 If-Match 헤더 필드와는 반대로 동작을 합니다. If-None_Match의 필드 값에 지정된 엔티티 태그 값이 지정된 리소스의 ETag 값과 일치하지 않으면 리퀘스트를 받아 들이겠다는 뜻입니다.
If-Range
이 헤더 필드는 조건부 리퀘스트의 하나로 If-Range로 지정한 필드 값과 지정한 리소스의 Etag 값 혹은 날짜가 일치하면 Range 리퀘스트로서 처리하고 싶다는 것을 전달합니다. 일치하지 않는 경우 리소스 전체를 반환합니다.
If-Range를 사용하지 않는다면 서버 측의 리소스가 갱신되어 있는 경우, 클라이언트 측에서 가지고 있는 리소스의 일부분은 무효한 것이 되기 때문에 Range 리퀘스트는 무효합니다. 이 경우에 서버는 일단 상태 코드 412 Precondition Failed 리스폰스를 반환하고 클라이언트에 다시 리퀘스트를 보내도록 재촉합니다. 따라서 더 많은 액션이 필요로 하게 됩니다.
웹 서버는 If-Range 헤더를 받게 되면, 컨텐츠가 변경된 경우는 새로운 컨텐츠 전체를 전달하고 변경되지 않은 경우는 Range 헤더 값에 해당되는 데이터만 전달하게 되는 것 입니다.
If-Unmodified-Since
이 헤더 필드는 If-Modified-Since 헤더 필드와 반대로 동작합니다. 지정된 리소스가 필드 값에 지정된 날짜 이후에 갱신되어 있지 않는 경우에만 리퀘스트를 받아들이도록 전달합니다. 지정된 날짜 이후에 갱신된 경우에는 상태 코드 412 Precondition Failed 리스폰스를 반환합니다.
Max-Forwards
이 헤더필드는 TRACE 혹은 OPTIONS 메소드에 의한 리퀘스트를 할 때에 전송해도 좋은 서버 수의 최대치를 10진수 정수로 지정합니다. 서버는 다음 서버에 리퀘스트를 전송할 때는 Max-Forwards 값에서 1을 빼서 다시 세트합니다. Max-Forwards 값이 0인 리퀘스트를 받은 경우에는 전송하지 않고 리스폰스를 반환할 필요가 있습니다.
HTTP를 사용한 통신에서는 리퀘스트가 프록시 서버 등 여러 대의 서버를 경유해 가는 경우가 있습니다. 도중에 프록시 서버에서 무언가의 원인으로 리퀘스트 전송이 실패하게 되면 클라이언트에는 리스폰스가 되돌아 오지 않기 때문에 알 수가 없습니다.
이러한 문제가 발생한 경우의 원인 조사에 Max-Forwards 헤더 필드는 활용됩니다.
Proxy-Authorization
이 헤더 필드는 프록시 서버에서의 인증 요구를 받아들인 때에 인증에 필요한 클라이언트의 정보를 전달합니다. 클라이언트와 서버의 HTTP 액세스 인증과 비슷한데 다른 점은 클라이언트와 프록시 사이에 인증이 이루어진다는 것 입니다. 클라이언트와 서버의 경우, Authrization 헤더 필드와 같은 역할을 합니다.
Range
이 헤더 필드는 리소스의 일부분만 취득하는 Range 리퀘스트를 할 때 지정 범위를 전달합니다. 이 헤더 필드가 달린 리퀘스트를 받아들인 서버가 리퀘스트를 처리할 수 있는 경우에는 상태 코드 206 Partial Content 리스폰스를 반환합니다. 이 리퀘스트를 처리할 수 없는 경우에는 상태코드 200 OK 를 반환하고 리소스 전체를 반환합니다.
Referer
이 헤더 필드는 리퀘스트가 발생한 본래 리소스의 URI를 전달합니다. 기본적으로 이 헤더 필드는 보내져야 하지만, 브라우저의 주소창에 직접 URI를 입력한 경우와 보안상 바람직하지 않다고 판단된 경우에는 보내지 않아도 괜찮습니다.
본래 리소스의 URI 쿼리에 ID 및 패스워드와 비밀 정보 등이 포함되어 있는 경우, 이 헤더 필드를 통해서 그 정보가 다른 서버에 누설되어 버릴 가능성이 있습니다.
TE
이 헤더 필드는 리스폰스로 받을 수 있는 전송 코딩의 형식과 상대적인 우선 순위를 전달합니다. Accept-Encoding 헤더 필드와 매우 비슷하지만 여기선 전송 코딩에 적용됩니다.
이 헤더 필드는 전송 코딩의 지정 이외에 Trailer를 동반하는 청크 전송 인코딩을 지정하는 것이 가능합니다. 이 경우, 필드 값이 Trailer라고 기록합니다.
💡 청크 인코딩 이란 메시지를 일정 크기의 청크 여럿으로 쪼갭니다. 서버는 각 청크를 순차적으로 보냅니다. 이 인코딩을 이용하면 메시지를 보내기 전에 전체 크기를 알 필요가 없어집니다. 본문이 동적으로 생성됨에 따라, 서버는 그 중 일부를 버퍼에 담은 뒤 그 한 청크를 그 것의 크기와 함께 보낼 수 있습니다. 본문 전체를 보낼 때까지 이 단계를 반복하게 됩니다.
HTTP/1.1 Response header field
리스폰스 헤더 필드는 서버 측으로부터 클라이언트 측으로 송신되는 리스폰스 메시지에 적용도니 헤더로 리스폰스의 부가 정보, 서버의 정보, 클라이언트에 부가 정보 요구 등을 나타냅니다.
Accept-Range
이 헤더 필드는 서버가 리소스의 일부분만 지정해서 취득할 수 있는 Range 리퀘스트를 접수할 수 있는지 여부를 전달합니다. 가능한 경우 bytes, 불가능한 경우 none을 기록합니다.
Age
이 헤더 필드는 얼마나 오래 전에 오리진 서버에서 리스폰스가 생성되었는지를 전달합니다. 프록시가 리스폰스를 생성했다면 이 헤더필드는 필수입니다.
ETag
이 헤더 필드는 엔티티 태그라고 불리며 일의적으로 리소스를 특정하기 위한 문자열을 전달합니다. 서버는 리소스마다 Etag값을 할당합니다.
ETag에는 강한 Etag값과 약한 Etag값이 존재하며, 약한 Etag값 앞에는 W/ 가 붙습니다.
Location
이 헤더 필드는 리스폰스의 수신자에 대해서 Request-URI 이외의 리소스 엑세스를 유도하는 경우에 사용됩니다. 대부분의 브라우저에서는 이 헤더 필드를 포함한 리스폰스를 받으면 강제로 리다이렉트 하는 곳의 리소스에 엑세스를 시도합니다.
Proxy-Authenticate
이 헤더 필드는 프록시 서버에서의 인증 요구를 클라이언트에게 전달합니다. 클라이언트와 서버와의 HTTP 엑세스 인증과 비슷한데 다른 점은 클라이언트와 프록시 사이에서 인증이 이루어진다는 것입니다. 클라이언트와 서버의 경우 WWW-Authorization 헤더 필드와 같은 역할을 합니다.
Retry-After
이 헤더필드는 클라이언트가 일정 시간 후에 리퀘스트를 다시 시행해야 하는지를 전달합니다.
Vary
이 헤더 필드는 캐시를 컨트롤하기 위해서 사용합니다. 오리진 서버가 프록시 서버에 로컬 캐시를 사용하는 방법에 대한 지시를 전달합니다. 오리진 서버로부터 Vary에 지정되었던 리스폰스를 받아들인 프록시서버는 이후 캐시된 때의 리퀘스트와 같은 Vary에 지정되어 있는 헤더 필드를 가진 리퀘스트에 대해서만 캐시를 반환할 수 있습니다. 같은 리소스에 대한 리퀘스트라도 Vary에 지정되었던 헤더 필드가 다른 경우에는 오리진 서버로부터 리소스를 취득할 필요가 있습니다.
WWW-Authenticate
이 헤더 필드는 HTTP엑세스 인증에 사용되는데 Request-URI에 지정했던 리소스에 적용할 수 있는 인증 스키마와 파라미터를 나타내는 과제를 전달합니다 이 헤더 필드는 상태 코드 401 Unauthroized 리스폰스에 반드시 포함됩니다.
HTTP/1.1 Entity header field
엔티티 헤더 필드는 리퀘스트 메시지와 리스폰스 메시지에 포함된 엔티티에 사용되는 헤더로 콘텐츠의 갱신 시간 같은 엔티티에 관한 정보를 포함합니다.
Allow
이 헤더 필드는 Request-URI에 지정된 리소스가 제공하는 메소드의 일람을 전달합니다.
서버가 받을 수 없는 메소드를 수신한 경우에는 405 Method Not Allowed 리스폰스와 함께 수신 가능한 메소드의 일람을 기술한 헤더를 반환합니다.
Contents-Encoding
이 헤더 필드는 서버가 엔티티 바디에 실시한 콘텐츠 코딩 형식을 전달합니다. 콘텐츠 코딩은 엔티티의 정보가 누락되지 않도록 압축할 것을 지시합니다.
💡 엔티티의 정보 누락과 더불어 요청이나 응답 전송 소모량등도 줄어들기 때문에 압축을 합니다.
Contents-Location
이 헤더 필드는 메시지 바디에 대응하는 URI를 전달합니다. Location 헤더 필드와 달리 Contents-Location은 메시지 바디로 반환된 리소스의 URI를 나타냅니다.
Contents-MD5
이 헤더 필드는 메시지 바디가 변경되지 않고 도착했는지 확인하기 위해 MD5 알고리즘에 의해서 생성된 값을 전달합니다. HTTP 헤더에는 바이너리 값을 기록하는것이 불가능 하기 때문에 Base64로 인코딩하고 있습니다.
💡 Base64란 Binary Data를 Text로 바꾸는 Encoding(binary-to-text encoding schemes)의 하나로써 Binary Data를 Character set에 영향을 받지 않는 공통 ASCII 영역의 문자로만 이루어진 문자열로 바꾸는 Encoding이다.
Expire
이 헤더 필드는 리소스의 유효 기한 날짜를 전달합니다. 캐시 서버가 이 헤더 필드를 포함한 리소스를 수신한 경우 필드 값으로 지정된 날짜까지 리스폰스의 복사본을 유지하고 리퀘스트에는 캐시로 응답합니다. 지정 날짜가 지난 경우에는 리퀘스트가 온 단계에서 오리진 서버에 리소스를 얻으러 갑니다.
HTTPS 및 보안
HTTP의 약점
HTTP의 약점은 다음과 같습니다.
- 평문 (암호화 하지 않은) 통신이기 때문에 도청이 가능하다.
- 통신 상대를 확인하지 않기 때문에 위장이 가능하다.
- 완전성을 증명할 수 없기 때문에 변조 가능하다.
이 약점은 HTTP뿐만이 아닌, 다른 암호화하지 않은 프로토콜에서도 공통되는 문제입니다. 그 밖에도 HTTP 자신의 약점은 몇 가지 있습니다. 또, 특정 웹 서버나 특정 웹 클라이언트의 구현상의 약점, JAVA, PHP 등으로 구축한 웹 어플리케이션 취약성등이 있습니다.
💡 PHP는 원격코드 실행, 크로스 사이트 스크립팅, SQL인젝션, 파일시스템공격 등에 취약합니다.
평문이기 때문에 도청 가능
HTTP를 사용한 리퀘스트나 리스폰스 통신 내용은 HTTP 자신을 암호화하는 기능이 없기 때문에 통신 전체가 암호화 되지는 않습니다. 즉, 평문으로 HTTP메시지를 보내게 됩니다.
TCP/IP는 도청 가능한 네트워크
암호화되지 않은 통신의 약점은 TCP/IP의 구조의 통신 내용은 전부 통신 경로의 도중에 엿볼수 있기 때문입니다. 인터넷은 전 세계를 경유하는 네트워크로 되어 있습니다. 어느 서버와 클라이언트가 통신을 할 때, 통신 경로 상에 있는 네트워크 기기나 케이블이나 컴퓨터 등을 전부 자기 자신이 소유하고 있는 일은 있을 수 없습니다. 그래서 악의를 가진 누군가가 엿볼 수 있습니다. 통신 내용을 엿볼 수 있다는 것은, 암호화된 통신에서도 암호화되지 않은 통신도 같습니다. 암호화 통신은 메시지 속의 의미는 간파할 수 없을 수도 있겠지만 암호화된 메시지 자체는 엿볼 수 있습니다.
💡 암호화 한다고 그 내용 자체를 보지 못하는 것은 아닙니다. 암호화된 내용을 상대는 볼 수 있습니다.
같은 세그먼트의 통신을 도청하는 것은 어려운 일이 아닙니다. 네트워크 상을 흐르고 있는 패킷을 수집하는 것만으로 도청할 수 있게 됩니다. 패킷을 수집하려면 패킷을 해석하는 패킷 캡처나 스니퍼라는 툴을 사용합니다.
암호화로 도청을 피하다
현재 도청으로부터 정보를 지키기 위한 방법이 몇 가지가 연구되고 있습니다. 그 중에서 가장 보급되어 있는 기술은 암호화입니다. 암호화에는 몇 가지의 대상이 있습니다.
통신 암호 SSL 및 TLS는 네트워크를 통해 작동하는 서버, 시스템 및 응용프로그램간에 인증 및 데이터 암호화를 제공하는 암호화 프로토콜입니다. SSL은 TLS의 이전의 프로토콜입니다. 수년동안 취약성을 해결하고 더 강력하고 안전한 암호화 제품군 및 알고리즘을 지원하기 위해 새로운 버전의 프로토콜이 출시되었습니다.
- 한 가지는 통신을 암호화하는 방법입니다. HTTP에는 암호화 구조는 없지만 SSL이나 TLS이라는 다른 프로토콜을 조합함으로써 HTTP의 통신 내용을 암호화할 수 있습니다. SSL 등을 이용해 안전한 통신로를 확립하고 나서 그 통신로를 사용해 HTTP통신을 합니다. SSL을 조합한 HTTP를 HTTPS나 HTTP over SLL이라고 불리고 있습니다.
- 콘텐츠 암호화
- 콘텐츠 암호화는 통신하고 있는 콘텐츠의 내용 자체를 암호화해버리는 방법입니다. HTTP에 암호화를 하는 기능은 없기 때문에 HTTP를 사용해서 운반하는 내용을 암호화하는 것입니다. 즉, HTTP 메시지에 포함되는 콘텐츠만 암호화하는 것입니다. 이 경우, 클라이언트에서 HTTP 메시지를 암호화해서 출력하는 처리가 필요하게 됩니다. 물론, 콘텐츠의 암호화를 유효하게 하기 위해서는 클라이언트와 서버가 콘텐츠의 암호화나 복호화의 구조를 가지고 있는 것이 전제가 되므로, 평상시에 유저가 사용하는 브라우저와 웹 서버에서는 이용하는 것이 어렵습니다. 주로 웹 서비스 등에서 이용되는 방법입니다.
통신 상대를 확인하지 않기 때문에 위장이 가능
HTTP를 사용한 리퀘스트나 리스폰스에서는 통신 상대를 확인하지 않습니다. 리퀘스트를 보낸 서버가 정말로 URI에서 지정된 호스트인지 아닌지, 리스폰스를 반환한 클라이언트가 정말로 리퀘스트를 출력한 클라이언트인지 아닌지를 모른다는 것입니다.
누구나 리퀘스트 할 수 있다
HTTP에 의한 통신에는 상대가 누구인지 확인하는 처리는 없기 때문에 누구든지 리퀘스트를 보낼 수 있습니다. 또한, 리퀘스트가 오면 상대가 누구든지 무언가의 리스폰스를 반환합니다. (단, IP주소나 포트 등에서 그 웹서버에 엑세스 제한이 없는 경우) HTTP는 누구이던 간에 리퀘스트를 보내면 리스폰스가 반환되는 매우 심플한 구조로 되어 있지만, 상대를 확인하지 않는 점이 약점일 수가 있습니다. 그 약점은 다음과 같습니다.
- 리퀘스트를 보낸 곳의 웹 서버가 원래 의도한 리스폰스를 보내야 하는 웹 서버인지 아닌지를 확인할 수 없다. 위장한 웹 서버일 우려가 있다.
- 리스폰스를 반환한 곳의 클라이언트가 원래 의도한 리퀘스트를 보낸 클라이언트인지 아닌지를 확인할 수 없다. 위장한 클라이언트일 우려가 있다.
- 통신하고 있는 상대가 접근이 허가된 상대인지 아닌지를 확인할 수 없다. 중요한 정보를 가진 웹 서버에서는 특정 상대만 통신을 허가하고 싶을 때가 있다.
- 어디의 누가 리퀘스트를 했는지를 확인할 수 없다.
- 의미없는 리퀘스트라도 수신하게 된다. 대량의 리퀘스트에 의한 DoS 공격을 방지할 수 없다.
상대를 확인하는 증명서
HTTP에서는 통신 상대를 확인할 수 없지만 SSL로 상대를 확인할 수 있습니다. SSL은 암호화뿐만 아니라 상대를 확인하는 수단으로 증명서를 제공하고 있습니다. 증명서는 신뢰할 수 있는 제3자 기관에 의해 발행되는 것이기 때문에 서버나 클라이언트가 실제하는 사실을 증명합니다. 또 그 증명서를 위조하는 것은 기술적으로 상당히 어렵습니다. 통신 상대의 서버나 클라이언트가 가진 증명서를 확인함으로써 통신 상대가 내가 통신하고자 하는 상대인지 아닌지를 판단할 수 있습니다. 이 증명서를 이용함으로써, 통신 상대가 내가 통신하고자 하는 서버임을 나타내고 이용자는 개인 정보 누설 등의 위험성이 줄어들게 됩니다.
완전성을 증명할 수 없기 때문에 변조 가능
완전성이란 정보의 정확성을 가리킵니다. 그것을 증명할 수 없다는 것은 정보가 정확한지 아닌지를 확인할 수 없음을 의미합니다.
수신한 내용이 다를지도 모른다
HTTP가 완전성을 증명할 수 없다는 뜻은 만약 리퀘스트나 리스폰스가 발신된 후 상대가 수신할 때까지의 사이가 변조되었다고 하더라도, 이 사실을 알 수 없다는 뜻입니다. 즉, 발신된 리퀘스트나 리스폰스와 수신한 리퀘스트나 리스폰스가 같은지 아닌지를 확인할 수 없다는 의미입니다.
예를 들어, 어떤 웹 사이트에서 콘텐츠를 다운로드 했다고 하면 클라이언트에 다운로드한 파일과 서버 상에 있는 파일이 정말로 같은 것인지 아닌지 모른다는 것입니다. 콘텐츠가 도중에 다른 내용으로 변경되었을지도 모릅니다. 만약에 콘텐츠가 다른 것으로 변경되었다 하더라도 수신한 측에서 알아챌 수 없습니다.
이와같이 공격자가 도중에 리퀘스트나 리스폰스르 빼앗아 변조하는 공격을 중간자 공격이라고 부릅니다.
변조를 방지하려면?
HTTP를 사용해서 완전성을 확인하기 위한 방법은 있지만, 확실하면서 편리한 방법은 현재로서 존재하지 않습니다. 그 중에서도 자주 사용되고 있는 방법은 MD5나 SHA-1등의 해시 값을 확인하는 방법과 파일의 디지털 서명을 확인하는 방법입니다. 그러나 이 방법으로 확실히 확인할 수 있는 것은 아닙니다. 그것은 PGP와 MD5 자체도 적절하게 수정되어 있다고 한다면, 유저로서는 알 수가 없습니다. 확실히 방지하기에는 HTTPS를 사용할 필요가 있습니다. SSL에는 인증이나 암호화, 그리고 다이제스트 기능을 제공하고 있습니다. HTTP만으로는 완전성을 보증하는 것이 어렵기 때문에 다른 프로토콜을 조합함으로써 실현하고 있습니다.
💡 다이제스트 기능이란, 비밀번호를 네트워크를 통해 평문으로 전송하지 않고, 인증 체결을 가로채서 재현하지 못하게 하고 메시지 위조 방지를 가능하게 합니다. 다이제스트 인증 핸드셰이크는 난스값을 계산하고 인증요구 메시지에 담아 서버가 지원하는 알고리즘 목록과 함께 클라이언트에 전송하고 클라이언트는 알고리즘을 선택, 비밀번호와 그 외 데이터에 대한 요약 계산을 하고 클라이언트는 Authrozation 메시지에 요약을 담아 서버로 전송, 서버를 인증하려면 클라이언트 난수를 보낼 수 있음, 서버는 요약, 알고리즘, 그 외 보조데이터를 받아 요약을 검증하고 클라이언트가 서버에게 인증을 요구했다면 클라이언트 요약이 만들어 클라이언트에 전송, 다음번 난스를 클라이언트에게 미리 전송하기도 합니다.
HTTP에 암호화와 인증과 완전성 보호를 더한 HTTPS
HTTP통신은 암호화되지 않은 평문으로 실시됩니다. 예를 들면 웹 페이지에서 신용 카드 번호를 입력했을 때 통신이 도청되면 신용 카드 번호를 도청당하게 됩니다.
또한, HTTP에는 통신 상대의 서버나 클라이언트를 인증하는 수단이 없습니다. 실제로는 의도한 통신 상대와 통신하고 있지 않을 가능성이 있습니다. 그리고 수신한 메시지가 도중에 변조되어 있을 가능성도 생각할 수 있습니다.
이러한 문제를 해결하기 위해서는 암호화와 인증과 완전성 보호 같은 구조를 HTTP에 추가할 필요가 있습니다. HTTP에 암호화나 인증 등의 구조를 더한 것을 HTTPS라고 부릅니다.
HTTPS를 사용하는 통신은 웹페이지의 로그인이나 쇼핑의 결제화면 등에서 사용되고 있습니다. HTTPS를 사용한 통신은 URI에 http://가 아닌 https:// 를 사용합니다. 또한, 브라우저에게 HTTPS가 유효한 웹 사이트에 엑세스하면 자물쇠 마크가 표시되는 등 HTTP와는 다르게 표시되는 경우가 있습니다.
HTTPS는 SSL의 껍질을 덮어쓴 HTTP
HTTPS는 새로운 애플리케이션 계층의 프로토콜은 아닙니다. HTTP 통신을 하는 소켓 부분을 SSL이나 TLS이라는 프로토콜로 대체하고 있을 뿐입니다.
보통 HTTP는 직접 TCP와 통신하지만 SSL을 사용한 경우에는 HTTP는 SSL와 통신하고 SSL이 TCP와 통신하게 됩니다. 즉, SSL이라는 껍질을 덮어 쓴 HTTP가 HTTPS인 것입니다.
SSL을 사용함으로써 HTTP는 HTTPS으로서 암호화와 증명서와 완전성 보호를 이용할 수 있게 됩니다. SSL은 HTTP와는 독립된 프로토콜로 HTTP만으로는 애플리케이션 계층에서 동작하는 SMTP나 Telnet 등에서도 이용될 수 있습니다. SSL은 현재 세계 어느 곳에서도 널리 사용되고 있는 네트워크 보안 기술이라고 말할 수 있습니다.
상호간에 키를 교환하는 공개키 암호화 방식
SSL을 설명하기 전에 암호화 방식에 대해서 설명합니다. SSL에서는 공개키 암호화 방식이라 불리는 암호화 방식을 채택하고 있습니다.
현대의 암호는 알고리즘이 공개되어 있고, 키를 비밀에 부침으로써 안전성을 유지합니다.
암호화나 복호화할 때 이 키를 사용합니다. 키가 없으면 암호를 풀 수는 없지만 반대로 생각해보면 키를 가지고 있다면 누구라도 암호를 풀 수가 있습니다. 공격자가 키를 알게 되면 암호화가 의미를 잃어버리게 됩니다.
공동키 암호의 딜레마
공동키 암호화 방식은 상대방에게 키를 넘겨주지 않으면 안됩니다. 그러나 어떻게 해서 안전하게 키를 상대해게 배송하면 좋을까? 네트워크를 사용해서 키를 넘겨줄 때 통신이 도청되어 공격자에게 키를 빼앗기게 되면 암호화의 의미가 없게 되어 버립니다. 또한, 받은 키를 안전하게 보관하기 위한 노력을 하지 않으면 안됩니다. 키를 보내면 도청될 가능성이 있고, 키를 보내지 않으면 복호화를 할 수 없는 딜레마에 빠지게 됩니다.
두 개의 키를 사용하는 공개키 암호
공동키 암호의 문제를 해결하려고 한 것이 공개키 암호라는 방식입니다. 공개키 암호에서는 서로 다른 두 개의 키 페어를 사용합니다. 한쪽은 비밀키(private key)라 부르고 다른 한쪽은 공개키(public key)라고 부릅니다. 이름대로, 비밀키는 누구에게도 알려지면 안되는 키이며 공개키는 누구에게나 알려져도 괜찮은 키입니다.
공개키 암호를 사용한 암호화는 암호를 보내는 측이 상대의 공개키를 사용해 암호화합니다. 그리고 암호화된 정보를 받아들인 상대는 자신의 비밀키를 사용해 복호화를 실시합니다. 이 방식은 암호를 푸는 비밀키를 통신으로 보낼 필요가 없기 때문에 도청에 의해서 키를 빼앗길 걱정은 없습니다.
HTTPS는 하이브리드 암호 시스템
HTTP는 공동키 암호와 공개키 암호의 양쪽 성질을 가진 하이브리드 암호 시스템입니다. 키를 안전하게 교환할 수만 있다면 공개키 암호만을 사용해서 통신을 해도 괜찮다고 생각할 지도 모르지만, 공개키 암호는 공통키 암호에 비해서 처리 속도가 늦습니다.
💡 공개키 암호는 공통키 암호보다 처리가 느리기 때문에, 모든 통신에 공개키 암호를 사용하는 것은 비효율적이다.
거기서 두 가지 장점을 살릴 수 있도록 각각의 방식을 조합해서 통신합니다. 키를 교환하는 곳에서는 공개키 암호를 사용하고 그 후의 통신에서 메시지를 교환하는 곳에서는 공통키 암호를 사용합니다.
공개키가 정확한지 아닌지를 증명하는 증명서
공개키 암호에도 문제점이 있습니다. 그 문제점은 공개키가 진짜인지 아닌지를 증명할 수 없다는 것입니다. 예를 들면, 어떤 서버와 공개키 암호를 사용해서 통신을 시작하려 할 때 수신한 공개키가 본래 의도한 서버가 발행한 공개키인지를 어떻게 증명할 수 있을까? 도중에 공격자가 공개키를 바꿔치기 했을지도 모릅니다.
이 문제를 해결하는 데는 인증 기관과 그 기관이 발행하는 공개키 증명서가 이용되고 있습니다. 인증 기관이란 클라이언트와 서버가 모두 신뢰하는 제3자 기관입니다. 유명한 인증 기관에는 VerSign사가 있습니다.
인증 기관은 다음과 같이 이용됩니다. 먼저 서버의 운영자가 인증 기관에 공개키를 제출합니다. 인증 기관은 제출된 공개키에 디지털 서명을 하고 서명이 끝난 공개키를 만듭니다. 그리고 공개키 인증서에 서명이 끝난 공개키를 담습니다.
서버는 이 인증 기관에 의해서 작성된 공개키 인증서를 클라이언트에 보내고, 공개키 암호로 통신을 합니다. 공개키 인증서는 디지털 증명서나 줄여서 증명서라고 부르는 경우도 있습니다. 증명서를 받은 클라이언트는 증명 기관의 공개키를 사용해서 서버의 공개키를 인증하는 것이 진짜 인증 기관이라는 것과 서버의 공개키가 신뢰할 수 있다는 것을 알 수 있습니다.
여기에서 사용되는 인증 기관의 공개키는 안전하게 클라이언트에 전달되지 않으면 안됩니다. 통신중에는 어떤 방법을 사용하더라도 안전하게 전달하는 것은 어렵기 때문에 대부분이 주요 인증 기관의 공개키를 사전에 내장한 상태로 제품을 내놓고 있습니다.
조직의 실제성을 증명하는 EV SSL 증명서
증명서의 역할은 서버가 올바른 통신 상대임을 증명하는 것이지만, 상대방이 실제로 있는 기업인지를 확인하는 역할도 있습니다. 그러한 역할을 가진 증명서를 EV SSL증명서라고 합니다.
💡 EV SSL 증명서는 세계 표준의 인정 가이드라인에 의해서 발행되는 증명서입니다. 운영하는 조직의 실재성을 확인하는 방법을 엄격히 규정하고 있기 때문에 웹 사이트의 신뢰성을 더욱 높일 수 있습니다.
브라우저의 주소창의 색이 녹색으로 변하면 EV SSL 증명서로 증명된 웹 사이트인 것을 시각적으로 알 수 있습니다. 그리고 주소창의 옆에는 SSL 증명서에 기재되어 있는 조직명 및 증명서를 발행한 인증 기관 명이 표시됩니다.
HTTPS의 구조
SLL handshake protocol
handshake protocol image - client hello 에서는 클라이언트가 생성한 난수, 가능한 암호방식, 이전 세션 아이디 (존재한다면)를 전송
- server hello 에서는 서버가 생성한 난수, 암호방식 전송
- certificate 는 server -> client 인증서 전송
- server_key_exchange 는 server -> client 간 키교환이 필요할 경우 사용된다.
- certificate_request 는 server -> client 필요한 경우 클라이언트 인증서 요청
- server_hello_done 은 서버에서 보낼 메세지는 모두 보냈다는 의미
- certificate 는 server 요청 시 인증서 전송
- client_key_exchange 는 pre master key를 서버의 공개키로 암호화하여 전송
- certificate_verify 는 요청시 자신이 보낸 인증서가 유효한지 전자서명을 보내는 메세지
- change_cipher_spec 는 클라이언트가 다음 메세지 부터 (암호, 키교환, 서명, 압축)방식을 적용 하여 전송하겠다는 메세지. finished 전송
- change_cipher_spec 는 위와 마찬가지 의미. 다음 finished 전송
이 흐름에 더해서 애플리케이션 계층의 데이터를 송신할 때에는 MAC(Message Authentication Code)이라고 부르는 메시지 다이제스트를 덧붙일 수 있습니다. MAC을 이용해서 변조를 감지할 수 있어서 완전성 보호를 실현할 수 있습니다.
SSL은 느리다?
HTTPS에도 문제가 있습니다. 바로 SSL을 사용하면 처리가 늦어지게 된다는 점 입니다.
SSL 통신이 지연되는 이유는 두 가지가 있습니다. 하나는 통신 속도가 떨어지는 것과, 다른 하나는 CPU나 메모리 등의 리소스를 다량으로 소비함으로써 처리가 느려지는 것입니다.
네트워크의 부하는 HTTP를 사용하는 경우에 비해 2배에서 100배 정도 느려질 수 있습니다. TCP접속과 HTTP의 리퀘스트, 리스폰스 이외에 SSL에 필요한 통신이 추가되기 때문에 전체적으로 처리해야 할 통신이 증가하게 됩니다.
다른 하나는 SSL은 반드시 암호화 처리를 하고 있기 때문에 서버나 클라이언트에서는 암호화나 복호화를 위한 계산을 할 필요가 있습니다. 그렇기 때문에 서버나 클라이언트의 리소스를 소비하게 되어 HTTP에 비해 부담이 커집니다.
느려지는 것에 대한 근본적인 해결 방법은 없기 때문에 SSL 악셀레이터라는 하드웨어를 사용해서 해결하기도 합니다. SSL의 처리만 SSL 악셀레이터에 맡김으로써 부하를 분산하도록 하고 있습니다.
HTTP Network에 대한 내용을 공부하기 위해 본 내용을 정리하며 기록한 내용입니다. 글에 오류가 있거나 사실과 다른 내용이 있으면 댓글 부탁드립니다! 감사합니다.