사용자 에이전트 클라이언트 힌트를 사용한 사용자 개인 정보 보호 및 개발자 환경 개선

User-Agent Client Hints는 Client Hints API에 새로 확장된 기능으로, 개발자는 이를 통해 개인 정보를 보호하고 인체공학적인 방식으로 사용자의 브라우저에 관한 정보에 액세스할 수 있습니다.

요아브 와이스
요아브 와이스

클라이언트 힌트를 사용하면 개발자가 사용자 에이전트 (UA) 문자열에서 파싱할 필요 없이 사용자의 기기 또는 조건에 관한 정보를 적극적으로 요청할 수 있습니다. 최종적으로 사용자 에이전트 문자열 세부사항을 줄이기 위한 첫 번째 단계는 이 대체 경로를 제공하는 것입니다.

대신 사용자 에이전트 클라이언트 힌트를 사용하기 위해 사용자 에이전트 문자열 파싱에 의존하는 기존 기능을 업데이트하는 방법을 알아봅니다.

배경

웹브라우저에서 요청할 때 서버가 분석을 사용 설정하고 응답을 맞춤설정할 수 있도록 브라우저 및 환경에 대한 정보가 포함됩니다. 이는 1996년 (HTTP/1.0의 경우 RFC 1945)에서 정의되었으며, 여기에서 사용자 에이전트 문자열의 원래 정의를 확인할 수 있습니다. 예를 들면 다음과 같습니다.

User-Agent: CERN-LineMode/2.15 libwww/2.17b3

이 헤더는 제품 (예: 브라우저 또는 라이브러리) 및 주석 (예: 버전)을 중요도 순으로 지정하도록 만들어졌습니다.

사용자 에이전트 문자열의 상태

그 사이에 수십 년 동안 이 문자열은 요청하는 클라이언트에 관한 다양한 추가 세부정보뿐만 아니라 이전 버전과의 호환성으로 인해 쓸모없는 정보가 수집되었습니다. Chrome의 현재 사용자 에이전트 문자열을 살펴보면 다음과 같은 것을 확인할 수 있습니다.

Mozilla/5.0 (Linux; Android 10; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4076.0 Mobile Safari/537.36

위의 문자열에는 사용자의 운영체제 및 버전, 기기 모델, 브라우저의 브랜드, 전체 버전에 관한 정보, 모바일 브라우저임을 추론할 수 있는 충분한 단서, 과거의 이유 때문에 다른 브라우저에 관한 언급이 여러 번 포함되어 있지 않습니다.

이러한 매개변수와 가능한 값의 다양성을 조합하면 사용자 에이전트 문자열이 개별 사용자를 고유하게 식별할 수 있는 충분한 정보를 포함할 수 있습니다. AmIUnique에서 자체 브라우저를 테스트하면 개발자의 사용자 에이전트 문자열이 사용자를 얼마나 가깝게 식별하는지 확인할 수 있습니다. 결과 '유사성 비율'이 낮을수록 요청의 고유성이 높을수록 서버가 은밀한 추적을 하기가 쉬워집니다.

사용자 에이전트 문자열은 합법적인 사용 사례를 많이 지원하며 개발자와 사이트 소유자에게 중요한 용도로 사용됩니다. 하지만 은밀한 추적 메서드로부터 사용자의 개인 정보를 보호하는 것도 중요하며 기본적으로 UA 정보를 전송하는 것은 이러한 목표에 방해가 됩니다.

또한 사용자 에이전트 문자열의 경우 웹 호환성을 개선해야 합니다. 구조화되지 않았으므로 이를 파싱하면 불필요한 복잡성이 발생하여 사용자에게 해를 끼치는 버그 및 사이트 호환성 문제의 원인인 경우가 많습니다. 또한 이러한 문제는 사이트가 구성 테스트에 실패했을 수 있으므로 덜 일반적인 브라우저의 사용자에게 특히 큰 피해를 줍니다.

새로운 사용자 에이전트 클라이언트 힌트 소개

사용자 에이전트 클라이언트 힌트를 사용하면 동일한 정보에 액세스할 수 있지만 개인 정보를 더욱 안전하게 보호할 수 있으므로 브라우저에서 사용자 에이전트 문자열의 모든 브로드캐스트를 기본값을 줄일 수 있습니다. 클라이언트 힌트는 서버가 브라우저에 클라이언트에 대한 데이터 세트(힌트)를 요청하고, 브라우저가 자체 정책 또는 사용자 구성을 적용하여 반환되는 데이터를 결정하는 모델을 시행합니다. 즉, 기본적으로 모든 사용자 에이전트 정보를 노출하는 대신 명시적이고 감사 가능한 방식으로 액세스가 관리됩니다. 개발자는 정규 표현식이 필요 없는 간단한 API의 이점도 누릴 수 있습니다.

현재 클라이언트 힌트 세트는 주로 브라우저의 표시 및 연결 기능을 설명합니다. 클라이언트 힌트로 리소스 선택 자동화에서 자세한 내용을 살펴볼 수 있지만 다음은 프로세스에 관한 간단한 복습입니다.

서버는 헤더를 통해 특정 클라이언트 힌트를 요청합니다.

⬇️ 서버의 응답

Accept-CH: Viewport-Width, Width

또는 메타 태그:

<meta http-equiv="Accept-CH" content="Viewport-Width, Width" />

그러면 브라우저는 후속 요청에서 다음 헤더를 다시 전송하도록 선택할 수 있습니다.

📊️ 후속 요청

Viewport-Width: 460
Width: 230

서버는 적절한 해상도로 이미지를 제공하는 등 응답을 다양하게 선택할 수 있습니다.

사용자 에이전트 클라이언트 힌트는 Accept-CH 서버 응답 헤더를 통해 지정할 수 있는 Sec-CH-UA 접두사를 사용하여 속성 범위를 확장합니다. 자세한 내용을 보려면 설명 내용으로 시작한 다음 전체 제안서를 살펴보세요.

Chromium 89의 사용자 에이전트 클라이언트 힌트

사용자 에이전트 클라이언트 힌트는 버전 89부터 Chrome에서 기본적으로 사용 설정되어 있습니다.

기본적으로 브라우저는 브라우저 브랜드, 주요 버전, 메이저 버전, 플랫폼, 클라이언트가 휴대기기인지 여부를 나타내는 표시기를 반환합니다.

📊️ 모든 요청

Sec-CH-UA: "Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "macOS"

사용자 에이전트 응답 및 요청 헤더

⬇️ 응답 Accept-CH
⬆️ 요청 헤더
⬆️ 요청
예시 값
설명
Sec-CH-UA "Chromium";v="84",
"Google Chrome";v="84"
브라우저 브랜드 및 주요 버전의 목록입니다.
Sec-CH-UA-Mobile ?1 브라우저가 휴대기기에 있는지 여부를 나타내는 부울 (true인 경우 ?1)입니다 (false인 경우 ?0).
Sec-CH-UA-Full-Version "84.0.4143.2" [지원 중단됨]브라우저의 전체 버전입니다.
Sec-CH-UA-Full-Version-List "Chromium";v="84.0.4143.2",
"Google Chrome";v="84.0.4143.2"
브라우저 브랜드 및 전체 버전 목록
Sec-CH-UA-Platform "Android" 기기의 플랫폼으로, 일반적으로 운영체제 (OS)입니다.
Sec-CH-UA-Platform-Version "10" 플랫폼 또는 OS의 버전입니다.
Sec-CH-UA-Arch "arm" 기기의 기본 아키텍처입니다. 페이지 표시와는 관련이 없을 수도 있지만 사이트에서는 올바른 형식으로 기본 설정된 다운로드를 제공하는 것이 좋습니다.
Sec-CH-UA-Model "Pixel 3" 기기 모델
Sec-CH-UA-Bitness "64" 기본 아키텍처의 비트율 (즉, 정수 또는 메모리 주소의 비트 단위 크기)

교환 예시

교환의 예는 다음과 같습니다.

📊️ 브라우저의 초기 요청
브라우저가 사이트에서 /downloads 페이지를 요청하고 기본 사용자 에이전트를 전송합니다.

GET /downloads HTTP/1.1
Host: example.site

Sec-CH-UA: "Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"
Sec-CH-UA-Mobile: ?1
Sec-CH-UA-Platform: "Android"

⬇️ 서버의 응답
서버에서 페이지를 다시 전송하고 추가로 전체 브라우저 버전과 플랫폼을 요청합니다.

HTTP/1.1 200 OK
Accept-CH: Sec-CH-UA-Full-Version-List

📊️ 후속 요청
브라우저는 서버에 추가 정보에 대한 액세스 권한을 부여하고 모든 후속 요청에서 추가 힌트를 다시 보냅니다.

GET /downloads/app1 HTTP/1.1
Host: example.site

Sec-CH-UA: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
Sec-CH-UA-Mobile: ?1
Sec-CH-UA-Full-Version-List: " Not A;Brand";v="99.0.0.0", "Chromium";v="98.0.4738.0", "Google Chrome";v="98.0.4738.0"
Sec-CH-UA-Platform: "Android"

JavaScript API

헤더와 함께 navigator.userAgentData를 통해 JavaScript에서 User-Agent에 액세스할 수도 있습니다. 기본 Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform 헤더 정보는 각각 brands 속성과 mobile 속성을 통해 액세스할 수 있습니다.

// Log the brand data
console.log(navigator.userAgentData.brands);

// output
[
  {
    brand: 'Chromium',
    version: '93',
  },
  {
    brand: 'Google Chrome',
    version: '93',
  },
  {
    brand: ' Not;A Brand',
    version: '99',
  },
];

// Log the mobile indicator
console.log(navigator.userAgentData.mobile);

// output
false;

// Log the platform value
console.log(navigator.userAgentData.platform);

// output
"macOS";

추가 값은 getHighEntropyValues() 호출을 통해 액세스됩니다. '높은 엔트로피'라는 용어는 정보 엔트로피를 참조합니다. 즉, 이러한 값이 사용자의 브라우저에 관해 공개하는 정보의 양을 나타냅니다. 추가 헤더 요청과 마찬가지로 반환되는 값은 브라우저에 달려 있습니다.

// Log the full user-agent data
navigator
  .userAgentData.getHighEntropyValues(
    ["architecture", "model", "bitness", "platformVersion",
     "fullVersionList"])
  .then(ua => { console.log(ua) });

// output
{
   "architecture":"x86",
   "bitness":"64",
   "brands":[
      {
         "brand":" Not A;Brand",
         "version":"99"
      },
      {
         "brand":"Chromium",
         "version":"98"
      },
      {
         "brand":"Google Chrome",
         "version":"98"
      }
   ],
   "fullVersionList":[
      {
         "brand":" Not A;Brand",
         "version":"99.0.0.0"
      },
      {
         "brand":"Chromium",
         "version":"98.0.4738.0"
      },
      {
         "brand":"Google Chrome",
         "version":"98.0.4738.0"
      }
   ],
   "mobile":false,
   "model":"",
   "platformVersion":"12.0.1"
}

데모

user-agent-client-hints.glitch.me를 통해 자신의 기기에서 헤더와 JavaScript API를 모두 사용해 볼 수 있습니다.

힌트 수명 및 재설정

Accept-CH 헤더를 통해 지정된 힌트는 브라우저 세션 기간 동안 또는 다른 힌트 세트가 지정될 때까지 전송됩니다.

즉, 서버가 다음을 전송하는 경우

⬇️ 응답

Accept-CH: Sec-CH-UA-Full-Version-List

그러면 브라우저가 닫힐 때까지 해당 사이트에 대한 모든 요청에 Sec-CH-UA-Full-Version-List 헤더를 전송합니다.

📊️ 후속 요청

Sec-CH-UA-Full-Version-List: " Not A;Brand";v="99.0.0.0", "Chromium";v="98.0.4738.0", "Google Chrome";v="98.0.4738.0"

그러나 다른 Accept-CH 헤더가 수신되면 브라우저가 전송하는 현재 힌트가 완전히 대체됩니다.

⬇️ 응답

Accept-CH: Sec-CH-UA-Bitness

📊️ 후속 요청

Sec-CH-UA-Platform: "64"

이전에 요청한 Sec-CH-UA-Full-Version-List전송되지 않습니다.

Accept-CH 헤더가 페이지에 필요한 전체 힌트 세트를 지정하는 것으로 생각하는 것이 가장 좋습니다. 즉, 브라우저에서 페이지의 모든 하위 리소스에 지정된 힌트를 전송합니다. 힌트는 다음 탐색에도 유지되지만, 사이트에서 힌트가 제공될 것이라고 예상하거나 의존해서는 안 됩니다.

또한 응답에 빈 Accept-CH를 전송하여 브라우저에서 전송하는 모든 힌트를 효과적으로 지울 수 있습니다. 사용자가 환경설정을 재설정하거나 사이트에서 로그아웃하는 모든 곳에 이 해시태그를 추가하는 것이 좋습니다.

이 패턴은 <meta http-equiv="Accept-CH" …> 태그를 통한 힌트 작동 방식과도 일치합니다. 요청된 힌트는 페이지에서 시작된 요청에만 전송되며 후속 탐색에서는 전송되지 않습니다.

힌트 범위 및 교차 출처 요청

기본적으로 클라이언트 힌트는 동일 출처 요청 시에만 전송됩니다. 즉, https://example.com에서 특정 힌트를 요청하지만 최적화하려는 리소스가 https://downloads.example.com에 있으면 어떠한 힌트도 받지 않습니다.

교차 출처 요청에 힌트를 허용하려면 각 힌트와 출처를 Permissions-Policy 헤더로 지정해야 합니다. 이를 사용자 에이전트 클라이언트 힌트에 적용하려면 힌트를 소문자로 바꾸고 sec- 접두사를 삭제해야 합니다. 예를 들면 다음과 같습니다.

⬇️ example.com의 응답

Accept-CH: Sec-CH-UA-Platform-Version, DPR
Permissions-Policy: ch-ua-platform-version=(self "downloads.example.com"),
                    ch-dpr=(self "cdn.provider" "img.example.com");

📊️ downloads.example.com 요청

Sec-CH-UA-Platform-Version: "10"

📊️ cdn.provider 또는 img.example.com 요청

DPR: 2

사용자 에이전트 클라이언트 힌트를 사용할 수 있는 위치

즉, 사용자 에이전트 헤더를 파싱하거나 동일한 정보 (예: navigator.userAgent, navigator.appVersion, navigator.platform)에 액세스하는 자바스크립트 호출을 활용하여 사용자 에이전트 클라이언트 힌트를 사용하는 모든 인스턴스를 리팩터링해야 합니다.

한 단계 더 나아가 사용자 에이전트 정보 사용을 다시 검토하고 가능한 경우 다른 메서드로 대체해야 합니다. 점진적 개선, 기능 감지 또는 반응형 디자인을 사용하여 동일한 목표를 달성할 수 있는 경우가 많습니다. 사용자 에이전트 데이터를 사용할 때의 기본적인 문제는 검사 중인 속성과 해당 속성이 사용 설정하는 동작 간의 매핑을 항상 유지한다는 것입니다. 이는 감지를 포괄적이고 최신 상태로 유지하기 위한 유지보수 오버헤드입니다.

이러한 주의사항을 염두에 두고 사용자 에이전트 클라이언트 힌트 저장소에는 사이트에 대한 몇 가지 유효한 사용 사례가 나열되어 있습니다.

사용자 에이전트 문자열은 어떻게 되나요?

이 계획은 기존 사이트에 지나친 중단을 유발하지 않으면서 기존 사용자 에이전트 문자열로 노출되는 식별 정보의 양을 줄여 웹에서 은밀한 추적 기능을 최소화하는 것입니다. 이제 사용자 에이전트 클라이언트 힌트를 도입하여 사용자 에이전트 문자열을 변경하기 전에 새로운 기능을 이해하고 실험해 볼 수 있습니다.

결국에는 사용자 에이전트 문자열의 정보가 줄어들어 기존 형식을 유지하면서 기본 힌트와 동일한 상위 수준 브라우저와 중요한 버전 정보만 제공합니다. Chromium에서는 생태계가 새로운 사용자 에이전트 클라이언트 힌트 기능을 평가할 수 있는 추가 시간을 제공하기 위해 이 변경사항을 최소 2022년까지 연기했습니다.

Chrome 93에서 about://flags/#reduce-user-agent 플래그를 사용 설정하여 이 버전을 테스트할 수 있습니다 (참고: Chrome 84~92 버전에서 이 플래그의 이름은 about://flags/#freeze-user-agent입니다). 그러면 호환성을 위해 이전 항목이 포함된 문자열이 반환되지만 정리된 세부사항은 포함됩니다. 예를 들면 다음과 같습니다.

Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Mobile Safari/537.36

Unsplash세르게이 졸킨 썸네일