Skip to content

[web.dev] Just the data you need #1

@dev-boku

Description

@dev-boku

시작하기에 앞서...

주의) 영어로 된 영상을 보면서 제가 잘못 번역했거나 잘못 이해한 부분이 있을 수 있습니다. 혹시 틀린 부분이 있다면 끝나고 바로 피드백 주세요. 그러면 시작해보겠습니다...

Just the data you need.

URL : https://www.youtube.com/watch?v=f0YY0o2OAKA&list=PLNYkxOF6rcIDJHOcBzho38p6WTn3vESvQ&index=11

웹은 원래 개방적이고 투명하게 설계되었습니다. 초기에는 브라우저의 작업 범위도 제한되었고 익명성, 상태가 없는 문서를 렌더링하고 이를 안전하게 유지하는데 도움이 되었습니다. 그러나 웹의 기능과 기대치가 계속 커지면서 그 어느때보다 개인정보보호보안이 중요하게 되었습니다.
사용자 데이터가 보안적 위협에 노출되지 않기 위해 솔루션을 생각하게 됐고, 3가지 질문 리스트를 만들게 됐습니다. 지금 이 글을 읽는 독자 또는 팀에게 다음 3가지 질문을 해보시기 바랍니다.

3가지 질문

1. Do I need this data?

개발자는 나중에 가치있을 수 있기 때문에 되도록 모든 데이터를 수집하고 싶어하는 생각이 있습니다. 하지만 이것은 좋은 생각이 아닙니다. 그리고 그 데이터가 유출되면 더 많은 리스크에 노출되게 됩니다. 따라야 할 규정도 많아지고 해야할 일도 더 많아지게 됩니다. 따라서 필요없는 데이터는 수집하지 않는게 좋습니다.

2. Is there an alternative?

대안에는 상황에 따라 다르고, 옵션도 너무 많습니다. 그래서 예를 들어보면 사이트 기본 설정과 같은 것은 서버에서 정보를 매번 획득하는 것도 좋지만 IndexedDB 또는 LocalStorage와 같은 클라이언트 측 스토리지를 사용하는 것이 더 좋을 수 있습니다. 서버와 최초에 동기화 시에 한 번만 요청하고 이후에는 필요하지 않을 수 있습니다. 때로는 쿠키가 정답인 경우도 있습니다.

3. Have I secured it correctly?

이전 강의에서 나온 것 처럼 First party 쿠키는 __Host- 접두사를 사용하여 안전하고 단일 출처가 되도록 해야합니다. 그리고 JavaScript가 쿠키에 접근하지 못하도록 HttpOnly를 사용해야 합니다. 또 사이트 간 요청 위조(Cross-Site Request Forgery)로부터 보호하기 위해 SameSite = Lax를 설정해야 합니다.

Set-Cookie : __Host-cookie name=cookievalue;Secure;Path=/;HttpOnly;

만약 Third party 쿠키라면 SameSite만 SameSite=None; Secure으로 설정하고 나머지는 동일하게 하면 됩니다.

Set-Cookie:
    first_party=cookievalue;
    SameSite=Lax

Set-Cookie:
    third_party=cookievalue;
    SameSite=None; Secure

SameSite=Lax 옵션은 Chrome 80 버전부터 default입니다.

만약 이 질문들에 대답을 할 수 있다면, 올바른 방향으로 가고있다고 생각할 수 있습니다. 그러면 다른 주제에 이 질문을 적용시켜보도록 하겠습니다.

User-Agent

User-Agent의 원래 사양은 1996년에 만들어 졌고 초기에는 매우 간단했습니다. 그러나 거의 25년의 세월이 지나면서 User Agent 문자열은 매우 커졌고 사용자의 브라우저, 디바이스의 정보들을 얻을 수 있습니다. 그래서 일반적이지 않은 디바이스를 사용하는 누군가를 추적하기에는 충분할 수 있습니다.

// 초기 User-Agent
// 기본적으로 브라우저 버전, 라이브러리 버전이 존재
User-Agent: CERN-LineMode/2.15 libwww/2.17b3

// 최근 User-Agent
User-Agent: Mozilla/5.0 (Linux; Android 10; Pixel3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4076.0 Mobile Safari/537.36

Q1) 이 데이터가 정말 필요합니까? (Do I need this data?)

feature support나 capabilities를 결정하기 위해 User Agent String을 사용하는 경우 feature detection, progressive enhancement, responsive design을 사용하는 것이 낫습니다. 즉 브라우저 버전과 기능을 매핑할 필요가 없습니다. 이렇게 하면 일반적이지 않은 브라우저를 제외할 가능성이 낮아지게 됩니다.

Q2) 다른 대안책이 있습니까? (Is there an alternative?)

User Agent를 사용하면 유용한 사례가 몇 가지 있습니다.

  • OS별로 적절한 UI를 보여줄 수 있습니다.
  • 특정 브라우저 버전에서 발생하는 버그를 해결할 때 도움이 됩니다.

이를 해결할 때 User Agent 대신 Client Hints를 사용해서 해결할 수 있습니다. Client Hints에 대한 자세한 소개는 아래에서 설명드리겠습니다.

Q3) 올바르게 획득했습니까? (Have I secured it correctly?)

User Agent 문자열은 기본적으로 노출되는 정보의 양이 많습니다. 또 User Agent는 정규식에 따라서 사용자를 Block시킬 가능성도 있습니다. 그래서 Client Hints를 사용하는 것을 권장합니다.
Client Hints은 기본적으로 same origin일 경우에만 사용할 수 있습니다. cross-origin 요청이 있는 경우에는 힌트 및 오리진 쌍의 정보를 응답 header에 넣어서 보내야합니다. 자세한 내용은 아래에서 설명하도록 하겠습니다.
그리고 Client Hints는 기본적으로 HTTPS에서만 전송됩니다. 이러한 특성 때문에 사용 시 주의가 필요합니다.

Client Hints

Server에서 Client Hint를 얻고 싶은 경우

  1. User-Agent를 사용할 때 각 요청에서 기본적으로 제공되는 기본 데이터는 브라우저에서 Sec-CH헤더 안에 이름, 중요 버전, 모바일 여부를 보냅니다.
Sec-CH-UA: "Chromium";v="84", "Google Chrome";v="84"
Sec-CH-UA-Mobile: ?0 // or (?1)
  1. 서버는 응답 헤더에 Accept-CH를 채워넣어 브라우저에게 추가 정보를 요청합니다. 아래 예제에서는 전체 브라우저 버전과 플랫폼을 요청해보겠습니다.
HTTP/1.1 200 OK
Accept-CH: UA-Full-Version, UA-Platform
  1. 브라우저는 후속 응답으로 서버에게 요청받은 추가 힌트를 보냅니다.
GET /downloads/app1 HTTP/1.1
Host: example.site

Sec-CH-UA: "Chromium";v="84", "Google Chrome";v="84"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Full-Version: "84.0.4143.2"
Sec-CH-UA-Platform: "Android"

JavaScript API를 이용해 얻는 경우

브라우저에서 기본적으로 제공해주는 User Agent 정보는 navigator.userAgentData를 통해서도 얻을 수 있습니다. 헤더를 통해 얻었던 Sec-CH-UA, Sec-CH-UA-Mobile 정보는 각각 brands값과 mobile값을 이용해서 얻을 수 있습니다.

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

// output
[
  {
    brand: 'Chromium',
    version: '84',
  },
  {
    brand: 'Google Chrome',
    version: '84',
  },
];

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

// output
false;

만약 추가적인 정보를 얻고 싶다면 getHighEntityValues() 메서드를 이용하면 됩니다. High Entropy라는 용어에서 쓰이는 Entropy는 정보 Entropy를 가리킨다고 합니다. 이 값을 이용해서 브라우저에게 필요한 정보를 요청할 수 있습니다.

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

// output
{
  "architecture": "x86",
  "model": "",
  "platform": "Linux",
  "platformVersion": "",
  "uaFullVersion": "84.0.4143.2"
}

image
(물리학에서만 듣던 Entropy를 봤을 때 저의 표정...) 혹시 Entropy라는 용어에 대해 알고 계신 분은 말씀 부탁드립니다..

더 많은 Client Hints 정보들이 있고, 자세한 내용은 여기를 참고하시길 바랍니다.

힌트의 scope와 cross-origin에서의 사용할 경우

위에서 언급한대로 client hintssame-origin에서만 사용할 수 있습니다. cross-origin에서도 힌트를 허용하려면 Feature-Policy 헤더를 이용해서 각 힌트-출처 쌍을 지정해야 합니다.

  1. Response example.com
Accept-CH: UA-Platform, DPR
Feature-Policy: ch-UA-Platform downloads.example.com;
                ch-DPR cdn.provider img.example.com
  1. Request downloads.example.com
Sec-CH-UA-Platform: "Android"

Refer(r)er

image
image

  1. 사용자가 site-one의 페이지를 방문한다고 가정
  2. 이미지를 로드하기 위해 site-two에 대한 요청 전송
  3. 경우에 따라 site-two는 referrer header를 통해 site-one의 전체 URL을 볼 수 있습니다. 전체 URL에는 Path, Query String을 민감한 정보나 개인정보가 포함될 수 있습니다.

Q1) 이 데이터가 정말 필요합니까? (Do I need this data?)

image
Referer요청이 어디에서 왔는지? 또는 동일한 출저인지 확인하기 위해 사용됩니다. 하지만 위 예제에서는 Referrer에 필요한 것보다도 훨씬 많은 데이터가 포함되어 있습니다. 이걸 해결하기 위해 Proxy를 사용하는 것도 대안이 될 수 있지만, 일이 더 많아질 수 있다는 단점이 있습니다.

Q2) 다른 대안책이 있습니까? (Is there an alternative?)

먼저 들어오는 요청(내부페이지로 접근)에 대해 설명하겠습니다. 만약 당신이 필요한 정보가 오리진이라면 POSTCORS 요청으로 이를 얻을 수 있습니다. 그리고 요청이 origin이 동일한 경우에는 Sec Fetch Site 헤더를 사용할 수 있습니다. 만약 사이트 간 요청 위조(CSRF)에 대한 방어가 필요하다면 CSRF Token을 이용해서 확인해야 합니다.

이제 나가는 요청(외부페이지로 이동)에 대해 설명하겠습니다. 이 때 Referrer-Policy를 설정해서 Referrer에 삽입되는 데이터를 제어할 수 있습니다. Referrer를 넣지 않을 수도 있고, Origin만 넣거나 Full URL을 넣을 수도 있습니다. Chrome 85부터는 strict-origin-when-cross-origin를 기본 Referer 정책으로 사용할 거라고 하는데요. strict-origin-when-cross-origin는 동일한 origin에 한해서만 전체 URL을 공유한다고 합니다.
image

Q3) 올바르게 획득했습니까? (Have I secured it correctly?)

strict-origin-when-cross-origin는 좋지만 전체 웹 사이트에 대해서 설정할 수는 없는 예외 케이스가 있을 수 있습니다. 이 때 바로 안전하지 않는 정책을 사용하지 말고 Case별로 접근해야 합니다. strict-origin-when-cross-origin을 기본 정책으로 사용하되 필요한 경우 단계별로 느슨한 정책을 설정합니다. Referrer Policy에 대한 자세한 정보는 여기를 참고해주세요.

Reference

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions