[새싹] 웹을 지탱하는 기술 Chapter09

채상엽·2022년 5월 10일
0

Sproutt 2nd - Spring Study

목록 보기
21/32

layout: post
title: "웹을 지탱하는 기술 스터디 - Chapter9"
date: 2022-04-23T00:00:00-00:00
author: sangyeop
categories: Sproutt-2nd


새싹 개발 서적 스터디 - 웹을 지탱하는 기술 Chapter09

Chapter 09. HTTP 헤더

HTTP 헤더의 중요성

  • 헤더는 메시지의 바디에 대한 부가적인 정보, 즉 메타 데이터를 표현한다.
  • 클라이언트와 서버는 헤더를 보고 메시지에 대한 동작을 결정한다.
  • 리소스에 대한 접근권한을 설정하는 인증 또는 클라이언트와 서버의 통신횟수 양을 감소시키는 캐시 같은 기능을 헤더로 구현한다.

날짜와 시간

Date

Date: Tue. 06 Jul 2010 03:21:05 GMT

HTTP에서는 일시는 모두 그리니치 표준시(GMT)로 기술하도록 되어 있다.

MIME 미디어 타입

메시지로 주고받는 리소스 표현의 종류를 지정하는 것이 MIME(Multipurpose Internet Mail Extensions) 미디어 타입이다. 원래 MIME 복수의 메일 헤더를 정의하는 스펙이지만, HTTP는 그 중 Content-Type 헤더 등 몇 개만을 이용한다.

Content-Type - 미디어 타입을 지정한다

바디 내용이 어떤 종류인가를 미디어 타입으로 나타낸다.

Content-Type: application/xhtml+xml; charset=utf-8

application/xhtml+xml이 미디어 타입이다. / 왼편을 '타입' 이라고 부르고, 오른편을 '서브타입' 이라고 부른다.

타입의 종류는 임의로 늘릴 수 없지만 서브 타입의 종류는 IANA의 웹 사이트에 소정의 형식을 등록하거나 접두어 'x-'를 붙여서 독자적인 서브타입을 만들 수도 있다.

타입의미
text사람이 읽고 직접 이해할 수 있는 텍스트text/plain
image그림 데이터image/jpeg
audio음성 데이터audio/mpeg
video동영상 데이터video/mp4
application그 밖의 데이터application/pdf
multipart복수의 데이터로 이루어진 복합 데이터multipart/related
message전자메일 메시지message/rfc822
model복수 차원으로 구성하는 모델 데이터model/vrml
example예시용example/foo-bar

charset 파라미터 - 문자 인코딩을 지정한다

위 예에서는 charset=utf-8 를 통해 UTF-8로 인코딩 하고 있음을 나타내고 있다. charset 파라미터는 생략이 가능하지만, 디폴트 문자 인코딩이 ISO 8859-1로 설정되어 있기 때문이다. 타입이 text인 경우에는 주의가 필요하다.

언어 태그

charset 파라미터는 문자 인코딩 방식을 지정하는 것이었지만 리소스 표현의 자연언어를 지정하는 Content-Language 헤더도 존재한다. 이 값은 '언어 태그' 라고 불리는 문자열이기도 하다.

Content-Language:ko-KR

-의 왼편 : 언어 코드가 들어간다(한국 : ko, 영어 : en)

-의 오른편 : 지역 코드가 들어간다(한국 : KR, 미국 : US, 영국 : GB)

콘텐트 네고시에이션

미디어 타입, 문자 인코딩, 언어태그를 서버가 일방적으로 결정하는 것 뿐 아니라 클라이언트와 네고시에이션해서 정의할 수 도 있다.

Accept - 처리할 수 있는 미디어 타입을 전달한다.

Accept: text/html, application/xhtml+xml, application/xml; q=0.9, */*;q=0.8

qvalue = q= 라는 파라미터 값을 의미하며, 미디어 타입의 우선순위를 나타낸다. 수치가 큰 쪽을 우선시 한다.

다음 예제는 클라이언트가 XML 형식 또는 Word 형식의 표현을 지정하고, 서버는 그에 대응할 수 없는 경우이다.

  • 요청
GET /test HTTP/1.1
Host: example.com
Accept: application/xml, application/msword:q=0.9
  • 응답
HTTP/1.1 406 Not Accpetable

클라이언트가 지정된 미디어 타입에 서버가 대응하고 있지 않다면 406 Not Accpetable을 반환한다.

Accept-Charset - 처리할 수 있는 문자 인코딩 전달하기

클라이언트가 자신이 처리할 수 있는 문자 인코딩을 서버에 전달할 때 사용한다.

Accept-Charset: EUC-KR:utf-8;q=0.7,*/*;q=0.7

기본 문자 인코딩은 ISO 8859-1이 qvalue의 기본 우선도 1이지만, 좀 더 구체적인 EUC-KR을 우선시 한다.

Accept-Language - 처리할 수 있는 언어를 전달한다

Accept-Language: ko, en-us;q=0.7,en;q=0.3

한국어가 기본값 1, 미국 영어가 0.7, 비특정 지역 영어가 0.3의 우선순위를 갖는다.

Content-Length와 청크(chunk) 전송

Content-Length - 바디의 길이를 지정한다

바디가 있는 경우 10진수의 바이트로 길이를 나타낸다. 미리 크기를 알고 있는 경우 다음과 같이 이용한다

Content-Length: 5538

청크 전송 - 바디를 분할하여 전송한다

그러나 크기가 동적인 경우 사이즈가 정해질 때까지 응답할 수 없기 때문에, 응답 성능이 저하된다. 이 때 사용하는 것이 Transfer-Encoding 헤더

Transfer-Endoding: chunked

이를 이용하면 최종적으로는 사이즈를 모르는 바디를 조금씩 전송할 수 있다. 각 청크의 시작에는 사이즈가 16진수로 들어가고 마지막은 반드시 길이가 0인 청크와 빈 줄을 붙인다.

인증

현재 주류인 HTTP 인증방식으로는 BasicDigest 인증 방식이 있다. 또한 웹 API에서는 WSSE라는 HTTP 인증의 확장 스펙을 이용하는 경우도 있다.

  • 요청
DELETE /test HTTP/1.1
Host: example.com
  • 응답
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Example.com"

WWW-Authenticate 헤더에 의해 서버가 제공하는 인증 방식을 이해할 수 있고, 그 방식에 따른 형식으로 인증 정보를 보낼 수 있다.

여기서는 서버는 Basic인증을 지원하고 realm은 서버상에서 이 리소스가 속한 URI 공간의 이름이 된다.

URI 공간 : URI 패스 이하를 가리키는 것이다. 예를 들면 http://example.com/foo라는 공간이 있다면 foo 뒤의 URI는 모두 URI 공간에 속한다.

Basic 인증

유저 이름과 패스워드에 의한 인증 방식. 유저 이름고 패스워드는 Authentication 헤더에 넣어서 요청마다 전송한다.

DELETE /test HTTP/1.1
Host: example.com
Authorization: Basc dXNIcjpwYXNzd29yZA==

인증방식(Basic)에 있어서, 유저 이름과 패스워드를 :로 연결하고 Base64 인코딩으로 한 문자열이 된다. 위의 암호처럼 보이는 문자열을 원래 문자열로 복원할 수 있다. 이는 유저 이름과 패스워드가 보통의 문자열로 네트워크에서 흘러다님을 의미한다. Basic인증을 사용할 경우 보안강도가 좋은지 등을 검토해야만 한다.

Digest 인증

Basic인증보다 보안이 강화된 인증 방식이다. 어떤 메시지에 대해 해시 함수를 적용한 해시 값을 의미한다.

해시함수란 ? : 데이터로부터 그 데이터를 대표하는 수치를 구하는 함수를 말한다. 여기서 얻어진 값을 해시 값이라고 한다.

챌린지

Digest 인증에서도 클라이언트는 우선 인증 정보 없이 요청을 송신한다. 그 결과로 인증이 실패하고 401 unauthorized가 돌아온다.

  • 요청
DELETE /test HTTP/1.1
Host: example.com
  • 응답
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest realm="example.com", nonce="1ac421d9e0a4k7q982z966p903372922", qop="auth, opaque="92eb5ffee6ae2fec3ad71c777531758f"

HTTPS 란? : HTTP와 SSL/TLS를 조합한 통신을 일컫는 말이다. 통신로를 암호화하고 클라이언트와 서버 간에 주고받는 데이터를 보호하여, 도청을 방지할 목적으로 사용한다.

SSL/TLS는 암호화, 인증, 변경감지 기능을 제공한다. HTTPS에서 통신할 경우, URI는 https를 사용하며 기본 포트 번호는 443번이다.

WWW-Athenticate 헤더 값을 '챌린지' 라고 부른다. 클라이언트는 챌린지를 사용하여 다음을 조립한다.

nonce : number used once, 모든 요청에 대해 변환하는 문자열이다. 생성할 해시 값의 보안을 좀 더 강화할 목적으로 사용한다.

qop : quality of protection, authauth-init을 지정한다. auth는 메서드와 URI로부터 다이제스트를 작성하지만 auth-init은 메서드와 URI를 추가해 메시지 바디도 이용한다.

opaque : 클라이언트에게 불투명한 문자열이다.

다이제스트의 생성과 송신

서버에서 인증에 필요한 정보를 얻었다면 자신의 유저 이름과 패스워드를 이용해 다이제스트를 생성한다.

  1. 유저 이름, realm, 패스워드는 :로 연결하고, MD5 해시 값을 구한다.
  2. 메서드와 URI의 패스를 :로 연결하고, MD5 해시 값을 구한다.
  3. 1의 값, 서버로부터 얻은 nonce, 클라이언트가 nonce를 보낸 횟수, 클라이언트가 생성상 nonce, qop 값, 2의 값을 :로 연결하고, MD5 해시 값을 구한다.

클라이언트는 생성한 다이제스트 값을 response라는 필드에 넣고 응답을 송신한다.

image

다이제스트 인증의 이점과 결점

  • 이점

    Basic 인증과는 달리, Digest 인증에서는 패스워드를 도둑맞을 위험이 없다. 또한 패스워드의 해시 값만 보관하면 되므로, 패스워드 자체를 서버에 맡겨두지 않아도 된다.

  • 결점

    • 패스워드만 암호화하기 때문에, 메시지 자체는 암호화 되지 않는다. 암호화 하기 위해서는 HTTPS를 이용해야 한다.
    • Basic의 경우에는 같은 URI 공간의 리소스에서 한번 인증되면, 두 번째 부터는 자동으로 유저 이름과 패스워드를 전송하지만, Digestnonce가 없다면 클라이언트에서 다이제스트를 계산할 수 없으므로, 요청할 때마다 한번은 401 Unauthorized를 얻어야 한다.

WSSE 인증

표준 외 방식이다. 여러 가지 인증방법을 사용하지 못할 경우에 어떻게든 패스워드를 그냥 흘려보내지 않고 인증하는 기구이다. WSSE 인증에서도 클라이언트는 우선 인증 정보 등으로 요청을 보내고, 서버로부터 401 Unauthorized 응답을 받는다.

  • 요청
DELETE /test HTTP/1.1
Host:example.com
  • 응답
HTTP/1.1 401 Unauthorized
WWW-Authenticate: WSSE realm="example.com",profile="UsernameToken"

profile은 현재 UsernameToken 만 준비되어있다. 클라이언트는 패스워드와 자신이 준비한 nonce와 일시를 연결한 문자열에 대해서 SHA-1 해시 값을 구해 Base64 인코딩을 한다. 이 값을 패스워드 다이제스트라고 한다.

image

서버는 데이터베이스에 보관하고있는 사용자 패스워드를 이용해 패스워드 다이제스트를 다시 계산하고, 그 값과 클라이언트가 신고한 값이 같으면 인증을 통과시킨다. 패스워드를 네트워크에 흘려보내지 않아도 되고,Digest만큼 복잡하지 않으면서 서버 측에서 패스워드를 그냥 보존해 둘 필요가 있으므로 BasicDigest 인증의 중간에 위치한 방식이라고 할 수 있다.

OpenID - 심플한 싱글 사인온

이 예를 들면 Yahoo! 계정으로 자작 웹 서비스에 로그인할 수 있게 되는 경우가 있다. 여기서 Yahoo! 처럼 웹 서비스 계정을 다른 웹 서비스에게 제공해주는 쪽을 Identity Provider라고 부르고, 이를 사용해 서비스를 제공하는 쪽을 Service Provider라고 부른다.

OAuth - 웹 서비스 사이의 권한의 위임

웹 서비스 간 데이터 교환을 위한 스펙이다. 앞의 예를 이어 가보자면 사진을 관리하고 제공하는 쪽을 Service Provider, 사진을 받아서 인쇄하는 쪽을 Consumer라고 한다. 사용자가 Service Provider 로부터 Consumer의 데이터를 넘기는데 동의하면 서로 데이터를 교환하는데, 이 기능을 인가 정보를 넘기는 기능이라고 부른다.

캐시

서버로부터 가져온 리소스를 로컬 스토리지(하드디스크 등)에 저장하여 재사용하는 방법을 말한다.

캐시용 헤더

클라이언트는 서버에서 가져온 리소스의 캐시 가능 여부를 조사하고 가능할 경우 로컬 스토리지에 저장한다.

Pragma - 캐시를 억제한다

HTTP/1.1 200 OK
Content-Type: application/xhtmll+xml, charset=utf-8
Pragma: no-cache

...

여기에 지정할 수 있는 값은 no-cahe 뿐이다. 이 값은 리소스를 캐시하지 말 것을 의미한다.

Expires - 캐시의 유효기간을 나타낸다

HTTP/1.1 200 OK
Content-Type: application/xhtmll+xml, charset=utf-8
Expires: Thu, 11 May 2010 16:00:00GMT

캐시 가능한 데이터

Expires 헤더는 최장 약 1년 이내로 유효기간을 설정할 것을 스펙에서 권장하고 있다.

Cache-Control - 상세한 캐시 방법을 지정한다

PragmaExpires 기능을 이 헤더로 완전 대용할 수 있다.

아래는 Pragmano-cache와 동일하며

Cacghe-Control: no-cache

아래는 Expires의 유효시간을 현재 시간으로부터 상대 시간으로 표현할 수 있다 (초 단위)

Cache-Control: max-age: 86400

캐시용 헤더의 사용 구분

  • 캐시를 시키지 않는 경우 no-cache 지정을 한다
  • 캐시의 유효기간이 명확한 경우에는 Expires를 이용해 절대시간으로 지정
  • 캐시의 유효기간을 상대적으로 지정하고자 할 경우에는 Cache-Controlmax-age를 이용한다

조건부 GET

ExpireCache-Control로 재사용 불가 판단이 되었더라도 조건부 GET을 송신하면 캐시를 재사용할 가능성이 생긴다. 조건부 GET은 리소스가 Last-Modified 또는 ETAG 헤더를 가지고 있을 때 이용할 수 있다.

If-Modified-Since - 리소스의 갱신일시를 조건으로 한다

  • 요청
GET /test HTTP/1.1
Host: example.com
if-Modified-Since: Thu, 11 May 2010 16:00:00 GMT
  • 응답
HTTP/1.1 304 Not Modified
Content-Type: application/xhtml+xml: charset=utf-8
Last-Modified: Thu, 11 May 2010 16:00:00 GMT

304 Not Modified는 조건부 GET에 대한 응답으로, 서버 리소스를 변경하지 않았음을 알려주는 상태 코드이다. 이 응답에는 바디가 포함되지 않기 때문에 네트워크 대역을 절약할 수 있다.

If-None-Match - 리소스의 ETag를 조건으로 한다

If-None-SinceLast-Modified 헤더에 의한 조건부 GET은 편하지만, 시계를 가지고 있지 않은 서버와 밀리 초 단위의 변경 가능성이 있는 리소스에는 이용할 수 없다. 이 때 사용하는 것이 ETag(엔티티태그) 이다.

GET /test2 HTTP/1.1
Host:example.com
If-None-Match: ab3322028

이는 '지정한 값과 매치 하지 않으면' 이라는 조건을 의미한다. 위의 GET의 결과로 서버상의 리소스가 변경되지 않았으면 다음의 응답을 반환한다.

HTTP/1.1 304 Not Modified
Content-Type: application/xhtml+xml: charset=utf-8
Etag: ab3322028

ETag는 갱신 상태를 비교하기 위해서만 사용하는 문자열 이므로, 어떤 문자라도 상관 없다.

ETag의 계산

  • 정적 파일

    inode 번호는 동일 내용의 파일이어도 파일 시스템이 다르면 다른 값이 되기 때문에, 파일 사이즈와 갱신 일시만으로 ETag 값을 계산하도록 설계할 수 있다.

  • 동적 파일

    정적 파일은 Apache 등의 웹 서버가 ETag를 계산해주지만 동적 파일의 경우에는 그렇지 않다. 일반적으로는 ETag 값 계산은 리소스 내용의 해시를 계산하는게 가장 간단하지만, 사이즈가 큰 리소스나 데이터베이스의 경우에는 리소스의 메타 데이터를 이용해서 생성하거나, 리소스의 갱신 카운터를 준비해서 대용하기도 한다.

If-Modfied-Since 와 If-None-Match의 사용 구분

클라이언트의 입장에서는 서버가 ETag 헤더를 보내고 있다면 갱신일자보다 ETag헤더가 정확하기 때문에 If-None-Match 헤더를 이용하는게 좋다. ETag가 없다면 If-Modified-Since를 사용한다.

지속적 접속

서버와 클라이언트 사이의 매 요청과 응답시마다 커넥션을 전달하는 것이 아니라, 계속해서 접속을 유지해 모아두는 기능이다. 지속적 접속에서는 클라이언트가 응답을 기다리지 않고 같은 서버에 요청을 송신할 수 있다. 이것을 파이프라인화라고 한다.

그 밖의 HTTP 헤더

Content-Disposition - 파일명을 지정한다

서버가 클라이언트에 대해 그 리소스의 파일명을 제공하기 위해 이용하는 응답 헤더이다.

Content-Disposition: attatchment: filename="rest.txt"

Slug - 파일명과 힌트를 지정한다.

Atom 엔트리를 Post 할 때 새로 생성할 리소스의 URI의 힌트가 되는 문자열을 서버에게 제시할 수 있다. 이때는 UTF-8의 %인코딩 방식을 사용한다.

profile
프로게이머 연습생 출신 주니어 서버 개발자 채상엽입니다.

0개의 댓글