[nginx] 기본값만 믿고 있다가 삽질하기 딱 좋은 설정 - 헤더의 언더스코어

Broccolism·2024년 6월 20일
3

dev-story

목록 보기
9/9

발단

  • 서버 A --> nginx --> 서버 B --> 서버 C
  • 서버 A에서 C로 HTTP request를 그대로 bypass해야 하는데, 특정 헤더가 전달되지 않는 상황

nginx 헤더 설정

nginx에는 유효하지 않은 헤더를 버리고 전달하는 옵션이 있다.

ignore_invalid_headers

유효하지 않은 헤더명을 가진 필드를 무시할 것인지에 대한 설정.

  • 기본값: on (무시)
  • 설정할 수 있는 값: on, off
  • 유효한 헤더의 조건:
    • 영어 알파벳, 숫자, 하이픈으로만 이루어진 헤더명
    • 언더스코어는 허용할 수도, 아닐 수도 있다. (언더스코어 허용 여부는 또다른 속성인 underscores_in_headers 에 따라 달라진다.)

underscores_in_headers

유효한 헤더의 조건으로, 언더스코어를 허용할 것인지에 대한 설정.

  • 기본값: off (허용하지 않음)
  • 설정할 수 있는 값: on, off

nginx 기본값의 조합으로 인해 당신의 헤더는 무시되었음.

짜잔~

  • underscores_in_headers: off 설정으로 인해 언더스코어를 포함한 헤더명은 invalid 해지고,
  • ignore_invalid_headers: on 설정으로 인해 그 invalid 한 헤더는 무시되었습니다!

그러면 이게 왜 기본값일까?

혹시 헤더명에 언더스코어가 있는게 HTTP 표준 규약에 맞지 않는 설정인걸까?

오. 비슷한 내용이 있다. RFC9110 문서를 살펴보자.

  • 우선 HTTP 규약에서는 데이터를 구조화해서 표현하기 위해 "field" 라는 개념을 사용한다.
  • 그 "field" 중, 진짜 보내고 싶은 필드는 "content", content 이전에 보내는 필드를 "header field", 혹은 "header" 라고 한다.
  1. Fields
    HTTP uses "fields" to provide data in the form of extensible name/value pairs with a registered key namespace.

6.3. Header Fields
Fields (Section 5) that are sent or received before the content are referred to as "header fields" (or just "headers", colloquially).

즉, 우리가 쓰는 헤더는 HTTP의 "필드" 종류 중 하나다. 그리고 그 필드의 이름에 대한 규약은 다음과 같다.

  • 사실 필드명에는 어떤 문자든 사용할 수 있지만, 특정 서버 구현체에서 받아들일 수 없는 문자열이 존재하기도 한다.
  • 따라서 모두가 해석 가능한 헤더명을 만들기 위해서는 영문 알파벳과 숫자, 하이픈, 온점을 사용하는 것을 권장한다.
  • 그리고 언더스코어는 몇몇 non-HTTP 게이트웨이 인터페이스에서 문제가 될 수도 있다고 하는데...

16.3.2.1. Considerations for New Field Names
(...) While the field-name syntax is defined to allow any token character, in practice some implementations place limits on the characters they accept in field-names. To be interoperable, new field names SHOULD constrain themselves to alphanumeric characters, "-", and ".", and SHOULD begin with a letter. For example, the underscore ("_") character can be problematic when passed through non-HTTP gateway interfaces (see Section 17.10).

헤더명으로 언더스코어를 쓰면 혼란스러워지는 경우: CGI

  • "some historical reason" 으로 인해, 몇몇 인터페이스에서는 자신이 받은 필드 이름을 그대로 넘겨주는게 아니라 환경 변수에 맞는 매핑 방식을 써서 이름을 변경한다.
  • 예를 들어 Common Gateway Interface(이하 CGI) 를 쓰면 자신이 받은 헤더 중, 미리 정의되지 않고 처음 보는 헤더명을 쓰고 있다면 앞에 "HTTP_" 라는 접두어를 붙이고, 모든 하이픈을 언더스코어로 바꿔버린다.
    • my-custom-header 필드는 HTTP_MY_CUSTOM_HEADER 라는 필드가 된다.

17.10. Application Handling of Field Names
For example, the Common Gateway Interface (CGI) mapping of protocol-specific meta-variables, defined by Section 4.1.18 of [RFC3875], is applied to received header fields that do not correspond to one of CGI's standard variables; the mapping consists of prepending "HTTP_" to each name and changing all instances of hyphen ("-") to underscore ("_"). This same mapping has been inherited by many other application frameworks in order to simplify moving applications from one platform to the next.

  • 따라서 여기선 하이픈을 쓰든 언더스코어를 쓰든 구분이 안 된다는 뜻이다.
    • 어떤 서버에서 my-custom-header_v2my-custom-header-v2 를 동시에 보냈다면 CGI 는 이걸 같은 헤더로 인식해버린다.

그러면 CGI 는 어디에 쓰이나?

  • 1990년대에 개발된 CGI는 아직도 쓰인다..고 하는데
  • 일단 CGI는 웹 서버에서 돌아가는 프로그램을 만드는 인터페이스이고 웹페이지에서 동적으로 실행되는 액션을 할 때 많이 쓰인다.
  • 예를 들면 사용자가 HTML form 을 채워넣고 클릭 버튼을 누르는 경우 처럼... 이게 뭔 소린고 하니...
  • 아마도 지금처럼 FE 웹서버와 BE 서버, DB 가 분리되어있지 않은 채로 웹서버를 개발했던 시절에 사용자가 입력한 값을 DB로 넘기기 위한 중간다리 역할을 하던 게이트웨이가 있었고, 그 게이트웨이에서 쓰던 인터페이스가 바로 이 CGI 아니었나 싶다.

https://www.geeksforgeeks.org/what-is-the-role-of-cgi-in-web-development/

  • 즉, 동적 웹페이지를 만드는 데 아주 중요한 역할을 했던 것이다.
  • 주로 C, Python, Perl 등으로 CGI 스크립트를 작성했고
  • 지금은 PHP, Ruby on Rails, Spring 등과 같은 기술로 대체되었지만
  • 임베디드 환경이나 PHP 를 지원하지 않는 환경 등에서는 여전히 쓰이고 있는 것 같다.
    https://stackoverflow.com/questions/1162029/what-are-cgi-scripts-used-for-these-days

결론

무슨 일이 일어날 지 모르니 HTTP 헤더명에는 되도록 언더스코어 대신 하이픈을 사용하자.

profile
설계를 좋아합니다. 코드도 적고 그림도 그리고 글도 씁니다. 넓고 얕은 경험을 쌓고 있습니다.

0개의 댓글