최신 웹 애플리케이션에서 사용자 데이터를 안전하게 호스팅

David Dworken
David Dworken

많은 웹 애플리케이션은 사용자가 제어하는 콘텐츠를 표시해야 합니다. 이는 사용자가 업로드한 이미지 (예: 프로필 사진)를 제공하는 것만큼 간단하거나 사용자가 제어하는 HTML을 렌더링하는 것 (예: 웹 개발 튜토리얼)만큼 복잡할 수 있습니다. 이는 항상 안전하게 하기가 어려웠기 때문에, Google은 대부분의 웹 애플리케이션 유형에 적용할 수 있는 간단하지만 안전한 솔루션을 찾기 위해 노력해 왔습니다.

신뢰할 수 없는 콘텐츠를 격리하는 기존 솔루션

사용자 제어 콘텐츠를 안전하게 제공하기 위한 기존 솔루션은 샌드박스 도메인이라는 것을 사용하는 것입니다. 기본 아이디어는 애플리케이션의 기본 도메인이 example.com이면 신뢰할 수 없는 모든 콘텐츠를 exampleusercontent.com에서 제공할 수 있다는 것입니다. 이 두 도메인은 크로스 사이트이므로 exampleusercontent.com의 악성 콘텐츠는 example.com에 영향을 미칠 수 없습니다.
이 접근 방식을 사용하면 이미지, 다운로드, HTML 등 신뢰할 수 없는 모든 종류의 콘텐츠를 안전하게 게재할 수 있습니다. 이미지나 다운로드에 이 기능을 사용할 필요가 없어 보일 수 있지만 이렇게 하면 특히 기존 브라우저에서 콘텐츠 스니핑의 위험을 피할 수 있습니다.
샌드박스 도메인은 업계 전반에서 널리 사용되고 오랫동안 잘 작동해 왔습니다. 하지만 두 가지 단점이 있습니다.

  • 애플리케이션은 콘텐츠 액세스를 단일 사용자로 제한해야 하는 경우가 많으며 이를 위해서는 인증 및 승인을 구현해야 합니다. 샌드박스 도메인은 의도적으로 쿠키를 기본 애플리케이션 도메인과 공유하지 않기 때문에 이를 안전하게 수행하기가 매우 어렵습니다. 인증을 지원하려면 사이트에서 기능 URL을 활용하거나 샌드박스 도메인에 별도의 인증 쿠키를 설정해야 합니다. 이 두 번째 방법은 많은 브라우저가 기본적으로 크로스 사이트 쿠키를 제한하는 최신 웹에서 특히 문제가 됩니다.
  • 사용자 콘텐츠는 기본 사이트에서 분리되지만 다른 사용자 콘텐츠와 분리되지는 않습니다. 이렇게 하면 악의적인 사용자 콘텐츠가 샌드박스 도메인의 다른 데이터를 공격할 위험이 있습니다 (예: 동일 출처 데이터 읽기).

또한 샌드박스 도메인은 리소스가 격리된 도메인으로 명확하게 세분화되기 때문에 피싱 위험을 완화하는 데 도움이 됩니다.

사용자 콘텐츠 제공을 위한 최신 솔루션

시간이 지남에 따라 웹은 진화함에 따라 이제 신뢰할 수 없는 콘텐츠를 더 쉽고 안전하게 제공할 수 있는 방법이 생겼습니다. 여기에는 여러 가지 접근 방식이 있으므로 현재 Google에서 널리 사용되는 두 가지 솔루션을 개괄적으로 살펴보겠습니다.

접근 방식 1: 비활성 사용자 콘텐츠 게재

사이트에서 비활성 사용자 콘텐츠 (예: 이미지 및 다운로드와 같이 HTML 또는 JavaScript가 아닌 콘텐츠)만 제공하면 되는 경우 이제 격리된 샌드박스 도메인 없이도 이 작업을 안전하게 수행할 수 있습니다. 두 가지 주요 단계가 있습니다.

  • 항상 Content-Type 헤더를 모든 브라우저에서 지원하고 활성 콘텐츠를 포함하지 않는 잘 알려진 MIME 유형으로 설정하세요 (확실하지 않다면 application/octet-stream가 안전한 선택입니다).
  • 또한 항상 아래 응답 헤더를 설정하여 브라우저에서 응답을 완전히 격리하도록 합니다.
응답 헤더 목적

X-Content-Type-Options: nosniff

콘텐츠 스니핑 방지

Content-Disposition: attachment; filename="download"

렌더링하지 않고 다운로드를 트리거합니다.

Content-Security-Policy: sandbox

별도의 도메인에서 제공된 것처럼 콘텐츠를 샌드박스 처리

Content-Security-Policy: default-src ‘none'

JavaScript 실행을 사용 중지합니다 (하위 리소스 포함).

Cross-Origin-Resource-Policy: same-site

페이지가 크로스 사이트에 포함되지 않도록 차단

이러한 헤더 조합은 애플리케이션이 응답을 하위 리소스로 로드하거나 사용자가 파일로 다운로드할 수 있도록 보장합니다. 또한 헤더는 CSP 샌드박스 헤더와 default-src 제한을 통해 브라우저 버그로부터 여러 계층의 보호를 제공합니다. 전반적으로 위에서 설명한 설정은 이러한 방식으로 제공되는 응답이 삽입 또는 격리 취약점으로 이어지지 않는다는 높은 수준의 확신을 제공합니다.

심층 방어

위의 솔루션은 일반적으로 XSS에 대한 충분한 방어를 나타내지만, 추가 보안 계층을 제공하기 위해 적용할 수 있는 다음과 같은 여러 가지 추가 강화 조치가 있습니다.

  • IE11과의 호환성을 위해 X-Content-Security-Policy: sandbox 헤더를 설정합니다.
  • 엔드포인트가 삽입되지 않도록 차단하도록 Content-Security-Policy: frame-ancestors 'none' 헤더를 설정합니다.
  • 격리된 하위 도메인에 샌드박스 사용자 콘텐츠를 배치하는 방식: <ph type="x-smartling-placeholder">
      </ph>
    • 격리된 하위 도메인에 사용자 콘텐츠를 제공합니다 (예: Google에서 product.usercontent.google.com와 같은 도메인 사용).
    • Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp를 설정하여 교차 출처 분리를 사용 설정합니다.

접근 방식 2: 활성 사용자 콘텐츠 제공

기존 샌드박스 도메인 방식의 약점 없이도 활성 콘텐츠 (예: HTML 또는 SVG 이미지)를 안전하게 제공할 수 있습니다.
가장 간단한 방법은 Content-Security-Policy: sandbox 헤더를 활용하여 브라우저에 응답을 격리하도록 지시하는 것입니다. 현재 모든 웹 브라우저가 샌드박스 문서에 대한 프로세스 격리를 구현하는 것은 아니지만, 브라우저 프로세스 모델을 지속적으로 개선하면 임베딩 애플리케이션에서 샌드박스 처리된 콘텐츠를 분리하는 기능이 개선될 수 있습니다. SpectreJS렌더러 침해 공격이 위협 모델을 벗어나는 경우 CSP 샌드박스를 사용하는 것으로 충분한 해결책이 될 수 있습니다.
Google은 샌드박스 도메인의 개념을 현대화하여 신뢰할 수 없는 활성 콘텐츠를 완전히 격리할 수 있는 솔루션을 개발했습니다. 핵심 아이디어는 다음과 같습니다.

  • 공개 접미사 목록에 추가된 새 샌드박스 도메인을 만듭니다. 예를 들어 exampleusercontent.com를 PSL에 추가하면 foo.exampleusercontent.combar.exampleusercontent.com가 크로스 사이트이므로 서로 완전히 격리될 수 있습니다.
  • *.exampleusercontent.com/shim와 일치하는 URL은 모두 정적 shim 파일로 라우팅됩니다. 이 shim 파일에는 message 이벤트 핸들러를 수신 대기하고 수신하는 모든 콘텐츠를 렌더링하는 짧은 HTML 및 JavaScript 스니펫이 포함되어 있습니다.
  • 이를 사용하기 위해 제품은 $RANDOM_VALUE.exampleusercontent.com/shim에 iframe 또는 팝업을 생성하고 postMessage를 사용하여 신뢰할 수 없는 콘텐츠를 shim에 전송하여 렌더링합니다.
  • 렌더링된 콘텐츠는 Blob으로 변환되고 샌드박스 처리된 iframe 내에서 렌더링됩니다.

기존 샌드박스 도메인 접근 방식과 달리 이 방식은 모든 콘텐츠가 고유한 사이트에서 완전히 격리됩니다. 또한 기본 애플리케이션이 렌더링할 데이터를 검색하도록 하면 더 이상 기능 URL을 사용할 필요가 없습니다.

결론

이 두 솔루션을 함께 사용하면 googleusercontent.com 같은 기존 샌드박스 도메인에서 서드 파티 쿠키 차단과 호환되는 더 안전한 솔루션으로 이전할 수 있습니다. Google은 이미 이러한 솔루션을 사용하기 위해 많은 제품을 마이그레이션했으며 내년에 더 많은 마이그레이션을 계획할 예정입니다.