학교에서 알려주지 않는 17가지 실무 개발 기술 14장

반응형

💡 필자가 책을 읽고, 몰랐던 부분이나, 특별히 메모할만한 내용을 추출하여 기록한 포스팅입니다. 책 내용 외에 추가 설명을 덧붙인 부분들이 있습니다

 


[학교에서 알려주지 않는 17가지 실무 개발 기술] 구매하러 가기 ⬇

 

학교에서 알려주지 않는 17가지 실무 개발 기술:문자열 인코딩부터 웹 필수 지식까지

COUPANG

www.coupang.com

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."


이전 포스팅(⬇)에서 이어집니다.

[책장파먹기] 학교에서 알려주지 않는 17가지 실무 개발 기술 Part2 요약

14. HTTP

HTTP 가 주고받는 데이터는 다음과 같다.

  • 웹 페이지 구성 요소: HTML, CSS, JS
  • 웹서비스 동작 외의 요소: JSON, XML
  • HTTP 멀티파트 또는 BASE64 인코딩 활용하여 주고받는 요소: 이미지, 영상, 파일

HTTPS 는 HTTP 에 전송계층보안(Transport Layer Security, TLS)을 더해 만든  HTTPS 프로토콜을 사용한다.

14.1. 무상태성

무상태성이란, 클라이언트가 서버에게 요청해보기 전에는 서버가 연결 가능한지(또는 응답이 가능한지) 알 수 없음을 의미한다. TCP 는 상태가 있는 프로토콜인데 반해 HTTP 는 상태가 없는 프로토콜이다.

 

클라이언트가 기다려야 하는 최대 시간 = 타임아웃 시간 * 재시도 횟수

상황에 따라(서버와 클라이언트의 위치 등) 최대 대기 시간을 적절히 설정해야 한다. (참고로 TCP 에서는, 타임아웃 기능은 직접 구현해야한다.)

 

HTTP 는 TCP 프로토콜을 기반으로 한 프로토콜이다. 

HTTP 요청이 이루어지기 전에 실질적으로는 연결을 맺기 위한 TCP 통신을 진행(SYN, SYN/ACK, ACK)하고,

HTTP 요청이 이루어진 뒤에는 연결을 끊기 위한 TCP 통신을 진행(ACK, FIN, FIN)한다.

 

HTTP는 TCP(바이너리 통신) 위에 텍스트 기반의 HTTP 헤더와 메시지를 사용하기 때문에 패킷의 크기가 크다. 따라서, 많은 사용자를 처리할 수록 HTTP 는 TCP 에 비해 느리다.

 

HTTP 는 요청마다 소켓 하나를 점유하기 때문에 메시지가 섞이는 문제가 생기지 않지만, TCP 는 모든 요청이 소켓 1개를 사용하기 때문에 모든 요청이 1개의 소켓 안에서 섞이기 때문에, 이를 별도의 요청 ID 와 같은 식별자를 사용하여 응답을 구분해야 한다.

 

결국 HTTP 는 구현이 간단하지만, 그만큼 메시지 자체가 무겁다. 반면, TCP 는 구현은 복잡하지만, 그만큼 메시지가 가볍다.

 

속도를 위해서 무조건 TCP 를 사용해야하는 것은 아니다. 보통 HTTP, TCP 메시지를 처리하는 시간의 차이보다 기능 로직을 처리하는 시간이 훨씬 길기 때문에, 메시지 처리시간은 상대적으로 덜 중요해지게 된다. 다만, 금융이나 게임 등의 서비스에서 단시간 내에 많은 데이터를 주고 받는 경우에는 TCP 와 같은 경량 프로토콜을 활용하여 메시지 처리 시간을 단축해보는 것을 고려해볼 필요가 있다.

 

14.3. HTTP 요청

요청 라인 - 요청 HTTP 의 첫번째 줄

다음 줄은 예시

GET / HTTP/1.1\r\n

 

아래와 같은 구성

<요청 메서드> <URL 경로> <HTTP 버전>\r\n

 

통신 시 URL 에 명시된 도메인 네임은(사람이 읽기 쉬운 주소) DNS 서비스를 통해 IP 주소로 변환된다. 

하나의 URL 은 여러 IP 주소를 가질 수 있다. 이를 통해 요청을 여러 서버로 분산시킬 수 있는데, 이를 라운드 로빈(round robin) 또는 DNS 로드 밸런싱(load balancing) 이라고 한다.

 

HTTP 버전

오늘날은 대부분 1.1 버전을 사용한다. 

 

1.0에 비해 1.1에서는 효율적인 연결을 위해 소켓 재사용을 요청과 관련된 keep-alive 헤더와, 언어 및 인코딩 지원을 위한 헤더가 추가되었다.

 

2.0에서는 웹 페이지 하나를 보기 위해 수십 번을 요청하는 문제를 해결하기 위해 응답을 병렬로 보낼 수 있도록 개선하고, 불필요한 오버헤드를 제거했다.

요청 헤더

  • Host, Accept
  • User-Agent
  • Content-Type
  • Content-Length
  • Connection: keep-alive
  • ... (생략)

등의 주요한 헤더가 있다.

 

Accept

Accept 는 클라이언트가 처리가능한 데이터 형태를 알려주는 키워드를 저장한다. (텍스트, json, 동영상, 이미지 등)

그 외에도 Accept-Encoding(e.g., DEFALTE, gzip), Accept-Language, Accept-Charset(e.g., UTF-8) 등이 있다.

 

User-Agent

구글은 User-Agent 에 불필요한 값이 너무 많고, 마케팅 용도로 사용자를 추적하는데 사용된다며 점진적으로 이 값을 사용하지 않기로 했다. 이를 본래 목적인 디버깅 및 브라우저 사용 현황 추적에 적합하게 활용하기 위해 Client-Hint 헤더에 넣을 것이라고 밝혔다.

 

Content-Type

Content-Type 은 '요청데이터의 body 형식'을 지정하는 헤더이다. Accept 와 같은 키워드로 구성된다. 가령, 다음과 같은 형식으로 Content-Type 을 지정할 수 있다.

text/html:charset=utf-8

multipart/form-data;boundary=<문자열>

application/json

 

MIME 타입

위와 같이 전송된 데이터의 형식을 지정하는 방식을 MIME 타입이라고 부른다. Multipurpose Internet Mail Extensions 의 약자이며, ASCII 문자만으로 구성되어야 했던 SMTP 프로토콜의 단점을 보완하기 위해 등장했고, 다양한 언어의 인코딩 방식및 바이너리 데이터를 전송할 수 있는 방식을 정의한다.

 

CSRF

서버에서 응답하는 메시지의 Content-Type 을 application/json 또는 text/plain 으로 설정하면, 해당 메시지 바디에 포함된 javascript 코드는 실행되지 않는다. 이렇게 헤더를 명확히 설정하는 것만으로도 악의적인 공격을 일차적으로는 막을 수 있다. 이와 같은 공격을 Cross Site Request Forgery(CSRF), `JSON 하이재킹` 이라고 부른다. 여기서 Forgery 는 '위조'를 뜻한다.

 

Content-Length

Content-Length 는 요청 바디의 길이를 의미한다. 실제 바디 길이와 다르다면, 서버가 응답 메시지를 모두 보내기 전에 비정상적으로 종료되었을 가능성이 있다.

 

Connection:keep-alive

Connection:keep-alive 는 매 요청/응답마다 소켓 연결을 끊었던 1.0 버전에서의 비효율적인 구조를 개선하기 위한 헤더이다. 이 헤더가 설정된 경우, 요청을 받은 서버는 응답을 보낸 후 타임아웃 시간 전가지는 소켓 연결을 끊지 않는다. 이 시간 내에 다시 요청이 들어온다면, 기존 소켓 연결을 활용하기 때문에, 불필요한 클라이언트와의 재연결을 하지 않아도 되기에 시간을 줄일 수 있고, 소켓을 낭비하지 않아도 된다. 타임아웃은 클라이언트가 설정할 수도 있으나, 서버에 설정된 값이 우선된다.

메시지 바디

메시지 바디에는 단순문자열이 담길 수도 있고, 이미지나 동영상 파일과 같은 바이너리도 저장이 가능하다. HTTP로 바이너리를 보내고자 할 때는 Base64 로 인코딩되어 전송된다.

 

GET, OPTIONS 메서드는 메시지 바디를 사용할 수 없다. 대신 URL 뒷부분에 쿼리스트링으로 데이터를 포함할 수 있다.

💡 OPTIONS 메서드는 서버에서 지원하는 메서드를 확인하는 용도로 사용한다. OPTIONS 메서드로 요청한 응답의 헤더에는 Allow 헤더가 포함되어있는데, 여기에 허용된 메서드들이 나열되어있다.
반응형

14.4. HTTP 응답

응답 라인 - 응답 HTTP 의 첫번째 줄

HTTP/1.0 200 OK

<HTTP 버전> <상태코드> <상태메시지>\r\n

 

주요 상태 코드

  • 200 OK
  • 201 Created
  • 301 Move Permanently, 주소 이전: 클라이언트는 301 응답을 받으면 응답의 Location 헤더 값에 명시되어있는 주소로 즉시 이동
  • 400 Bad Request
  • 401 Unauthorized
  • 404 Not Found
  • 405 Method Not Allowed, 허용된 메서드가 아님
  • 500 Internal Server Error
  • 502 Bad Gateway
  • 503 Service Unavailable
  • 504 Gateway Timeout

14.5. 세션과 쿠키

HTTP 는 기본적으로 무상태(stateless) 프로토콜이므로, 서버는 요청이 어떤 클라이언트로부터 발생했는지 알 수 없다. 요청의 주체에 대한 정보를 파악하기 위해 '쿠키'를 사용한다.

 

새 연결 VS 기존 연결

쿠키와 세션id 를 활용하여 어떤 요청이 이전 요청이 존재하는 요청인지, 새로운 연결인지를 알 수 있다.

쿠키를 활용한 통신은 다음과 같은 절차로 이루어진다.

 

  1. 클라이언트가 서버에 최초 요청시 서버에서는 세션아이디를 만들어낸다.
  2. 서버는 1.에서 생성한 세션아이디를 서버쪽에 저장한다.
  3. 서버는 1.에서 생성한 세션아이디를 클라이언트에 응답한다. 이 때 Set-Cookie 라는 응답헤더를 활용한다.
    • Set-Cookie: sessionId=12345-12345-12345...
  4. 응답을 받은 클라이언트 브라우저는 3.에서 받은 쿠키를 브라우저에 저장한다.
  5. 다시 클라이언트의 요청이 발생하면, 브라우저는 4.에서 저장해두었던 쿠키 정보를 요청 헤더 Cookie 에 넣어 서버로 전송한다.
    • Cookie: sessionId=12345-12345-12345...
  6. 서버는 Cookie 헤더에 포함된 세션아이디가 1.에서 발급한 세션아이디와 비교하여 요청자를 검증할 수 있다.

세션아이디

Nginx 서버는 세션아이디를 구분하는 key 로 `sessionId` 를 사용하고, 

Apache 서버는 세션아이디를 구분하는 key 로 `jsessionid` 를 사용한다.

만약, Nginx, Apache 를 모두 사용하여 서버를 구성한 경우에, 두 서버 간 통신 시 세션 Id 가 달라 서로 인식하지 못하는 경우가 있을 수 있으므로 OAuth 토큰 등을 활용하여 새 연결인지, 기존 연결을 맺은 클라이언트인지 확인해야한다.

쿠키 만료시간 설정

Max-Age 응답헤더를 활용하여 쿠키가 만료될 시간을 초 단위로 설정할 수 있고,

Expires 응답헤더를 활용하여 쿠키가 만료될 시점을 날짜 및 시간(UTC String, e.g., "Mon, 09 Mar 2020 08:13:24 GMT")으로 지정할 수 있다.

 

보통의 브라우저에서는 Max-Age 가 Expires 에 비해 우선하며, 쿠키 만료시간이 설정되지 않으면 해당 쿠키는 클라이언트가 종료(보통 브라우저저의 종료)될 때 사라진다.

쿠키와 보안

  • 클라이언트측의 쿠키는 조작 가능하다. 쿠키는 언제나 변조될 가능성이 있음을 염두에 둔다.
  • GDPR 에 따르면, 쿠키에 의해 수집된 정보를 투명하게 공개해야 하며, 클라이언트의 쿠키 수집 거부했을 때의 불이익도 없어야 한다.
  • 제 삼자로부터 쿠키를 보거나 변조 방지하기
    • Secure 옵션: Https 통신인 경우에만 쿠키를 서버로 전송
    • HttpOnly 옵션: 웹 브라우저에서 javascript 코드로 cookie 에 접근하는 것을 방지

14.6. 스티키 세션

서비스의 확장에 따른 서버의 수평적확장시, 로드밸런싱에 의해 서로 다른 서버간에 쿠키를 이용하는 데 어려움이 생길 수 있다. 스티키세션은 연결이 이루어진 다음에는 해당 서버와의 통신만이 가능하도록 하는 기능이다.

 

로드벨런서는 첫 요청의 쿠키에 지정된 웹 서버가 등록되도록 한다. 첫 연결 이후의 요청부터는, 로드벨런서가 쿠키에 등록된 웹서버 정보를 가지고 요청을 할당한다. 스티키 세션에는 유지기간을 설정하게 되는데, 이 유지기간은 서버에서 발급하는 쿠키의 만료기간보다 길게 잡도록 하는 것이 좋다. 그렇지 않으면 서비스 이용 중에 세션을 발급한 서버가 아닌 다른 서버로 요청이 될 수도 있기 때문이다.

 

14.7. CORS

Cross-Origin Resource Sharing 는 서버의 자원(API, 파일) 등을 특정 호스트로 접속한 웹 브라우저만 사용할 수 있게 제한하는 정책이다. 

 

Same Origin Policy

Same Origin Policy(동일 출처 정책) 는 브라우저로 특정 호스트에 접속(e.g., section.cafe.naver.com)한 경우 해당 도메인 외의 도메인(section.blog.naver.com)에는 요청하지 못하게 하는 정책이다. 

 

이 정책으로, 다른 웹 사이트에서 무단으로 이미지, 동영상 등의 자원을 사용하지 못하게 할 수 있다.

 

CORS

하지만, 프론트엔드 서버와 백엔드 서버가 같은 서비스 제공자에 의해 운영되고 있음에도 의도적으로 분리되어있을 수 있는데, 이런 경우에 서로간에 자원을 공유할 수 있도록 허용하는 정책이 CORS 이다.

 

주의해야할 것은, CORS 는 브라우저단에서 사전에 지정하지 않은 도메인으로의 호출을 막을 뿐, 해킹된 웹 서버에서 자바스크립트가 실행되거나, 민감한 데이터가 유출되는 것, XSS 같은 공격을 막을 수 있는 것은 아니다.

CORS 단순 요청

다음 조건을 만족할 때 단순 요청으로 리소스를 요청할 수 있다. 자원을 제공하는 서버가 자원을 요청하는 서버의 도메인을 허용하기만 하면 별다른 검증 없이 '교차 출처 리소스 공유'를 할 수 있다.

  • GET, HEAD, POST 메서드 중 하나인 경우
  • POST 인 경우에는 Content-Type 헤더가 다음 중 하나인 경우
    • text/plain
    • application/x-www-form-urlencoded
    • multipart/form-data
  • 표준에 정의되지 않은 헤더를 사용하지 않은 경우

요청하는 브라우저측 요청헤더에는 브라우저가 접속해있는 서버의 도메인이 Origin 헤더의 값으로 전달된다.

요청받은 서버측에서 응답한 응답헤더에는 Access-Control-Allow-Origin 에 허용된 도메인 목록이 값으로 포함되어 전달된다. 보통 *(와일드카드)가 포함된 도메인, 또는 다른 서브도메인을 목록을 담고 있다.

CORS 사전 요청

'CORS 단순 요청'조건에 부합하지 않는 경우, 브라우저는 별도의 검증을 요구한다. 'CORS 사전 요청(OPTIONS 메서드)'이 그것이다. 가령, '표준에 정의되지 않은 헤더'를 사용하려고 한다거나, DELETE 메서드를 사용한다거나, POST 요청시 지정된 MIME 타입 외의 타입을 사용하려고 할 때가 해당할 수 있다.

 

표준이 아닌 임의의 헤더(My-HTTP-Custom-Header)를 POST 요청으로 보내고자 한다고 가정하자. 

 

브라우저는 먼저 CORS 단순 요청이 아니기 때문에 이를 허용하지 않을 것이다. 

따라서, 먼저는 다음과 같이 서버에 요청한다.

 

브라우저:

OPTIONS /data HTTP1.1

Origin: A

Access-Control-Request-Method: POST

Access-Control-Request-Headers: My-HTTP-Custom-Header

 

서버응답:

HTTP/1.1 200 OK

Access-Control-Allow-Origin: A 또는 *

Access-Control-Allow-Method: POST, GET, OPTIONS

Access-Control-Allow-Headers: My-HTTP-Custom-Header

 

이러한 사전요청 이후 브라우저는 method, headers 의 내용이 일치하는 것을 확인한 뒤, 서버에 요청을 진행하게 된다. 

 

14.8. Apache 와 Nginx

개발자가 HTTP 표준에 부합한 웹 서버를 처음부터 만들기는 매우 어렵고 비효율적인 일일 것이다. 당장 요청처리, 정적파일 캐시, 로드밸런스, 압축 및 보안 기능등 고려해야할 것들이 한 두 가지가 아니다.

 

Apache 와 Nginx 는 HTTP 표준을 구현한 웹 서버 소프트웨어이다. 20년 전부터 사용되어왔기에 그 안정성이 입증됐고, 인증을 비롯한 많은 기능을제공한다. 

 

Apache 는 사용자 수가 늘어날수록 다중 프로세스 구조를 사용하는 반면, Nginx 는 수평적 확장에 유리한 단일스레드와 이벤트 기반으로 동작한다. 따라서 많은 사용자 수를 처리하기에는 Nginx 가 더욱 유리하다. 

 

14.9. 마치며

HTTP 2.0 과 웹소켓은 '웹상에서의 비동기 통신 지원'을 목적으로 한다.

  • HTTP 2.0: 요청에 대한 여러 응답을 병렬로 보내는 데 초점
  • 웹소켓: 데이터의 양방향 통신에 초점

[학교에서 알려주지 않는 17가지 실무 개발 기술] 구매하러 가기 ⬇

 

학교에서 알려주지 않는 17가지 실무 개발 기술:문자열 인코딩부터 웹 필수 지식까지

COUPANG

www.coupang.com

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."


 

반응형

Designed by JB FACTORY