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

David Dworken
David Dworken

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

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

사용자가 제어하는 콘텐츠를 안전하게 제공하는 기본적인 방법은 샌드박스 도메인을 사용하는 것입니다. 기본적인 개념은 애플리케이션의 기본 도메인이 example.com이면 exampleusercontent.com에서 신뢰할 수 없는 모든 콘텐츠를 제공하는 것입니다. 이러한 두 도메인은 크로스 사이트이므로 exampleusercontent.com의 모든 악성 콘텐츠가 example.com에 영향을 미치지 않습니다.
이 접근 방식을 사용하면 이미지, 다운로드, HTML 등 신뢰할 수 없는 모든 종류의 콘텐츠를 안전하게 제공할 수 있습니다. 이미지 또는 다운로드에 이 기능을 사용할 필요가 없는 것처럼 보일 수 있지만, 이렇게 하면 특히 기존 브라우저에서 콘텐츠 스니핑으로 인한 위험을 방지할 수 있습니다.
샌드박스 도메인은 업계 전반에서 널리 사용되며 오랫동안 효과를 발휘해 왔습니다. 하지만 여기에는 두 가지 큰 단점이 있습니다.

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

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

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

시간이 지남에 따라 웹이 발전함에 따라 신뢰할 수 없는 콘텐츠를 제공하는 더 쉽고 안전한 방법이 생겨났습니다. 여기에는 여러 가지 방법이 있지만 현재 Google에서 널리 사용되는 두 가지 솔루션을 간략히 소개하겠습니다.

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

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

  • 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'

자바스크립트 실행을 사용 중지합니다 (하위 리소스 포함).

Cross-Origin-Resource-Policy: same-site

페이지가 크로스 사이트에 포함되지 않도록 합니다.

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

심층 방어

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

  • IE11과의 호환성을 위해 X-Content-Security-Policy: sandbox 헤더를 설정합니다.
  • 엔드포인트가 삽입되지 않도록 차단하도록 Content-Security-Policy: frame-ancestors 'none' 헤더를 설정합니다.
  • 다음을 수행하여 격리된 하위 도메인에서 사용자 콘텐츠를 샌드박스화합니다.
    • 분리된 하위 도메인에 사용자 콘텐츠 제공 (예: 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은 샌드박스 도메인의 개념을 현대화하여 신뢰할 수 없는 활성 콘텐츠를 완전히 분리할 수 있는 솔루션을 개발했습니다. 핵심 아이디어는 다음과 같습니다.

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

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

결론

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