User agent란 무엇이고, 어떤 포맷으로 만들어야하는지 알아보자.
🔸User agent란?
User agent의 사용 목적
User agent는 클라이언트가 어떤 환경에서 요청을 보냈는지 설명하는 필드이다.
우리가 user agent에 아무 정보도 주지 않고 구글에 'user agent'를 검색하는 요청을 날렸다고 생각해보자.
서버 입장에서는 이 요청을 보낸 사용자가 브라우저는 어떤걸 쓰는지, os를 뭘 쓰는지, 버전은 몇인지 알 방법이 없다.
아무리 응답의 유연성을 높인다해도 오늘날의 클라이언트 환경은 너무도 다양하기에, 사용자의 환경을 알지 못하면 기껏 서버가 응답을 보내도 제대로 작동하지 않을 수 있다.
이러한 이유로 RFC 9110에서는 서버측에서 거부하는게 아닌 이상 반드시 User agent에 사용 환경을 담아서 보내라고 말한다.
User agent가 포함되는 위치
이걸 설명하려면 우선 HTTP request message의 구조에 대해 알아야한다. 아래 사진을 보자.
HTTP request message는 크게 요청을 정의하는 Request line, header, 그리고 body로 나뉜다.
Header는 다시 Request, general, representation header 이렇게 세가지로 나뉘는데, User agent는 이중 Request header에 속한다.
Request header에는 user agent 외에도 expect, from를 포함한 5개의 다른 필드도 가질 수 있지만, 5개 중 가장 중요하게 여겨지는 것은 user agent 필드이다.
🔸User agent 생성 규칙
이제 user agent가 무엇을 위한 것인지 이해했으니, 실제로 어떤 포맷으로 제공해야하는지 알아보자.
먼저 구글에 'my user agent'를 검색해서 내 실행 환경에 대한 예시를 얻어보자. 지금은 단어와 괄호가 띄어쓰기를 기준으로 나열되어있다는 것만 보이면 된다.
// Mac
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/115.0
// Mobile
User-Agent: Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36
User agent의 구조
위 예시에서 볼 수 있듯이, 기본적으로 "User-Agent: "라는 문자열 뒤에 여러 블럭을 띄어쓰기로 연결하는 구조이다.
하나의 블럭은 product identifier라고 불리며 아래와 같은 구성을 가진다.
제품이름(필수) / 제품버전(선택) (0개 이상의 코멘트)
아래 네가지 유형 모두 유효한 product identifier들이다.
1. 프로덕트 이름만 있는 유형
Mobile
*프로덕트 버전에 별명이 있는 경우, slash(/) 뒤에 적어줘야한다.
2. 프로덕트 이름과 버전만 있는 유형
Gecko/20100101 Firefox/115.0 Chrome/114.0.0.0 Safari/537.36
3. 프로덕트 이름과 코멘트가 조합된 유형
MyProduct (Additional Information; About this product)
*코멘트는 semi colon(;) 으로 구분한다.
4. 모든 정보를 포함하는 유형
Mozilla/5.0 (Linux; Android 10; K) Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) AppleWebKit/537.36 (KHTML, like Gecko)
지켜야할 규칙
1. User agent에는 제품을 식별할 수 있는 정보만 추려서 보내야한다.
A sender SHOULD limit generated product identifiers to what is necessary to identify the product;
a sender MUST NOT generate advertising or other nonessential information within the product identifier.
A user agent SHOULD NOT generate a User-Agent header field containing needlessly fine-grained detail
and SHOULD limit the addition of subproducts by third parties.
RFC에서 User agent에 대한 설명 중 절반은 할애하여 강조하는 내용이다.
user agent에 과한 정보가 들어가게 되면 두가지 문제점이 생긴다. 첫째는 사용자를 특정할 수 있게된다는 것, 둘째는 요청 지연시간이 늘어난다는 것이다.
가장 대표적인 실수는 제품 고유번호 등을 user agent에 담아서 전송하는 것이다. 서버가 이런 정보를 사용하지 않는다면 다행이겠지만, 안전한 authentication 과정을 스킵하고 user agent를 오용하는 상황이라면 문제가 생긴다. 다른 클라언트가 랜덤 문자열을 제품 고유번호로 전송하면서 다른 사람의 고유번호를 알아낼 수도 있고, 제품키를 활용해서 다른 사람의 정보를 훔쳐볼 수도 있게 된다.
이 외에도 맞춤형 광고에 사용될 수 있는 정보 등도 user agent에서 제외시키는 것이 좋다.
2. 중요한 product identifier를 앞쪽에 배치해야한다.
꼭 user agent에만 적용되는 규칙은 아니고, 이렇게 나열하는 것이 관례이다. comment를 나열할 때도 이 규칙은 성립한다.
참고한 자료
RFC 9110: HTTP Semantics - https://www.rfc-editor.org/rfc/rfc9110#name-user-agent
Stack overflow - What is the standard format for a browser's User-Agent string?
MDN Browser Specific User-Agent - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent