layout: post
title: "웹을 지탱하는 기술 스터디 - Chapter9"
date: 2022-04-23T00:00:00-00:00
author: sangyeop
categories: Sproutt-2nd
Date
Date: Tue. 06 Jul 2010 03:21:05 GMT
HTTP에서는 일시는 모두 그리니치 표준시(GMT)로 기술하도록 되어 있다.
메시지로 주고받는 리소스 표현의 종류를 지정하는 것이 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 - 바디의 길이를 지정한다
바디가 있는 경우 10진수의 바이트로 길이를 나타낸다. 미리 크기를 알고 있는 경우 다음과 같이 이용한다
Content-Length: 5538
청크 전송 - 바디를 분할하여 전송한다
그러나 크기가 동적인 경우 사이즈가 정해질 때까지 응답할 수 없기 때문에, 응답 성능이 저하된다. 이 때 사용하는 것이 Transfer-Encoding
헤더
Transfer-Endoding: chunked
이를 이용하면 최종적으로는 사이즈를 모르는 바디를 조금씩 전송할 수 있다. 각 청크의 시작에는 사이즈가 16진수로 들어가고 마지막은 반드시 길이가 0인 청크와 빈 줄을 붙인다.
현재 주류인 HTTP 인증방식으로는 Basic
과 Digest
인증 방식이 있다. 또한 웹 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 공간에 속한다.
유저 이름과 패스워드에 의한 인증 방식. 유저 이름고 패스워드는 Authentication
헤더에 넣어서 요청마다 전송한다.
DELETE /test HTTP/1.1
Host: example.com
Authorization: Basc dXNIcjpwYXNzd29yZA==
인증방식(Basic)에 있어서, 유저 이름과 패스워드를 :
로 연결하고 Base64 인코딩으로 한 문자열이 된다. 위의 암호처럼 보이는 문자열을 원래 문자열로 복원할 수 있다. 이는 유저 이름과 패스워드가 보통의 문자열로 네트워크에서 흘러다님을 의미한다. Basic
인증을 사용할 경우 보안강도가 좋은지 등을 검토해야만 한다.
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, auth
나 auth-init
을 지정한다. auth
는 메서드와 URI로부터 다이제스트를 작성하지만 auth-init
은 메서드와 URI를 추가해 메시지 바디도 이용한다.
opaque
: 클라이언트에게 불투명한 문자열이다.
서버에서 인증에 필요한 정보를 얻었다면 자신의 유저 이름과 패스워드를 이용해 다이제스트를 생성한다.
:
로 연결하고, MD5
해시 값을 구한다.:
로 연결하고, MD5
해시 값을 구한다.nonce
, 클라이언트가 nonce
를 보낸 횟수, 클라이언트가 생성상 nonce
, qop
값, 2의 값을 :
로 연결하고, MD5
해시 값을 구한다.클라이언트는 생성한 다이제스트 값을 response
라는 필드에 넣고 응답을 송신한다.
이점
Basic
인증과는 달리, Digest
인증에서는 패스워드를 도둑맞을 위험이 없다. 또한 패스워드의 해시 값만 보관하면 되므로, 패스워드 자체를 서버에 맡겨두지 않아도 된다.
결점
HTTPS
를 이용해야 한다.Basic
의 경우에는 같은 URI 공간의 리소스에서 한번 인증되면, 두 번째 부터는 자동으로 유저 이름과 패스워드를 전송하지만, Digest
는 nonce
가 없다면 클라이언트에서 다이제스트를 계산할 수 없으므로, 요청할 때마다 한번은 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
인코딩을 한다. 이 값을 패스워드 다이제스트라고 한다.
서버는 데이터베이스에 보관하고있는 사용자 패스워드를 이용해 패스워드 다이제스트를 다시 계산하고, 그 값과 클라이언트가 신고한 값이 같으면 인증을 통과시킨다. 패스워드를 네트워크에 흘려보내지 않아도 되고,Digest
만큼 복잡하지 않으면서 서버 측에서 패스워드를 그냥 보존해 둘 필요가 있으므로 Basic
과 Digest
인증의 중간에 위치한 방식이라고 할 수 있다.
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 - 상세한 캐시 방법을 지정한다
Pragma
와 Expires
기능을 이 헤더로 완전 대용할 수 있다.
아래는 Pragma
의 no-cache
와 동일하며
Cacghe-Control: no-cache
아래는 Expires
의 유효시간을 현재 시간으로부터 상대 시간으로 표현할 수 있다 (초 단위)
Cache-Control: max-age: 86400
캐시용 헤더의 사용 구분
no-cache
지정을 한다Expires
를 이용해 절대시간으로 지정Cache-Control
의 max-age
를 이용한다Expire
와 Cache-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-Since
와 Last-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
를 사용한다.
서버와 클라이언트 사이의 매 요청과 응답시마다 커넥션을 전달하는 것이 아니라, 계속해서 접속을 유지해 모아두는 기능이다. 지속적 접속에서는 클라이언트가 응답을 기다리지 않고 같은 서버에 요청을 송신할 수 있다. 이것을 파이프라인화라고 한다.
Content-Disposition - 파일명을 지정한다
서버가 클라이언트에 대해 그 리소스의 파일명을 제공하기 위해 이용하는 응답 헤더이다.
Content-Disposition: attatchment: filename="rest.txt"
Slug - 파일명과 힌트를 지정한다.
Atom
엔트리를 Post
할 때 새로 생성할 리소스의 URI의 힌트가 되는 문자열을 서버에게 제시할 수 있다. 이때는 UTF-8의 %인코딩
방식을 사용한다.