동일 출처 정책

동일 출처 정책은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호 작용할 수 있는 방법을 제한하는 중요한 보안 메커니즘입니다.

잠재적 악성 문서를 격리하여 가능한 공격 벡터를 줄이는 데 도움이 됩니다. 예를 들어 인터넷의 악의적인 웹사이트가 브라우저에서 JS를 실행하여 (사용자가 로그인 한) 타사 웹메일 서비스나 회사 인트라넷(공용 IP 주소가 없어 공격자의 직접적인 접근으로부터 보호)에서 데이터를 읽고 공격자에게 전달하는 것을 방지합니다.

출처 정의

프로토콜, 포트(명시된 경우), 그리고 호스트가 같은 경우 두 URL은 동일한 출처를 가집니다. 이것을 "스키마/호스트/포트 튜플" 또는 그냥 "튜플"로 참조되는 것을 볼 수도 있을겁니다. ("튜플"은 함께 전체를 구성하는 항목 집합입니다. 이중/삼중/사중/오중 등의 일반적인 형식입니다.)

아래 표는 URL http://store.company.com/dir/page.html의 출처를 비교한 예시입니다.

| URL | 결과 | 이유 | | ------------------------------------------------- | --------- | ------------------------------------------- | --- | | http://store.company.com/dir2/other.html | 동일 출처 | 경로만 다름 | | http://store.company.com/dir/inner/another.html | 동일 출처 | 경로만 다름 | | https://store.company.com/page.html | 실패 | 다른 프로토콜 | | http://store.company.com:81/dir/page.html | 실패 | 다른 포트 (http:// 는 기본적으로 80 포트) | | http://news.company.com/dir/page.html | 실패 | 다른 호스트 | |

출처 상속

about:blank 또는 javascript: URL이 있는 페이지에서 실행된 스크립트는 해당 URL이 포함된 문서의 출처를 상속합니다. 이러한 유형의 URL에는 원본 서버에 대한 정보가 포함되어 있지 않기 때문입니다.

예를 들어 about:blank는 부모 스크립트가 내용을 작성하는(예: Window.open() (en-US) 메커니즘을 통해) 비어 있는 새 팝업 창의 URL로 자주 사용됩니다. 이 팝업에도 JavaScript가 포함되어 있다면 해당 스크립트는 팝업을 생성한 스크립트와 같은 출처를 상속합니다.

data: URL은 새로운 빈 보안 컨텍스트를 받습니다.

파일 출처

최신 브라우저는 일반적으로 file:/// 스키마를 사용하여 로드된 파일의 출처를 불투명한 출처로 취급합니다. 이는 파일에 동일한 폴더(예시로)에 있는 다른 파일이 포함된 경우, 같은 출처에서 온 것으로 간주되지 않으며 CORS 오류가 발생할 수 있다는 것을 뜻합니다.

URL 사양에 따르면 파일의 출처는 구현에 따라 다르며 일부 브라우저는 보안에 영향을 미치더라도 같은 디렉토리 또는 하위 디렉토리에 있는 파일을 동일한 출처로 취급할 수 있습니다.

출처 변경

경고: 여기에 설명된 접근 방식(document.domain setter 사용)은 동일 출처 정책에서 제공하는 보안 보호를 약화시키고 브라우저의 출처 모델을 복잡하게 하여 상호 운용성 문제와 보안 버그로 이어지기 때문에 더 이상 권장되지 않습니다.

페이지는 일부 제한 사항과 함께 자신의 출처를 변경할 수 있습니다. 스크립트는 document.domain의 값을 현재 도메인 또는 현재 도메인의 상위 도메인으로 설정할 수 있습니다. 현재 도메인의 상위 도메인으로 설정하면 더 짧은 상위 도메인이 동일 출처 검사에 사용됩니다.

예를 들어 http://store.company.com/dir/other.html에 있는 문서의 스크립트가 다음을 실행한다고 가정해보겠습니다.

js
document.domain = "company.com";

그런 다음, 페이지는 http://company.com/dir/page.html과의 동일 출처 검사를 통과할 수 있습니다. (http://company.com/dir/page.html 이를 표시하기 위해 document.domain"company.com"으로 설정한다고 가정합니다. 자세한 내용은 document.domain을 참조하십시오.) 그러나 othercompany.comcompany.com의 상위 도메인이 아니므로 company.com에서 document.domainothercompany.com으로 설정할 수 없습니다.

포트 번호는 브라우저에서 별도로 확인합니다. document.domain = document.domain을 포함하여 어떤 방식으로든 document.domain을 호출하면 포트 번호가 null로 덮어쓰입니다. 따라서 처음 대상에만 document.domain = "company.com"을 설정하면 company.com:8080company.com과 통신할 수 없습니다. 포트 번호가 모두 null이 되도록 둘 다 설정해 줘야 합니다.

이 메커니즘에는 몇 가지 제한 사항이 있습니다. 예를 들어 document-domain (en-US) Permissions-Policy (en-US)가 활성화되었거나, 문서가 샌드박스된 <iframe> (en-US)에 있는 경우 "SecurityError" DOMException (en-US)이 발생하며, 이러한 방식으로 출처를 변경하더라도 많은 Web API에서 사용되는 출처 확인에는 영향을 미치지 않습니다. (예: localStorage, indexedDB, BroadcastChannel, SharedWorker). 실패 사례의 전체 목록은 Document.domain > Failures에서 찾을 수 있습니다.

참고: 하위 도메인이 상위 도메인에 액세스하도록 허용하기 위해 document.domain을 사용하는 경우 상위 도메인과 하위 도메인 모두에서 document.domain을 같은 값으로 설정해야 합니다. 이는 상위 도메인을 원래 값으로 다시 설정하는 경우에도 필요합니다. 이렇게 하지 않으면 권한 오류가 발생할 수 있습니다.

교차 출처 네트워크 접근

동일 출처 정책은 XMLHttpRequest이나 <img> 요소를 사용하는 경우와 같이 서로 다른 두 출처 간의 상호 작용을 제어합니다. 이러한 상호 작용은 일반적으로 세 가지 범주로 분류됩니다.

  • 교차 출처 쓰기는 보통 허용합니다. 예시로는 링크, 리다이렉트, 그리고 양식 제출 등이 있습니다. 일부 HTTP 요청은 프리플라이트를 요구합니다.
  • 교차 출처 삽입은 보통 허용합니다. (예시는 아래에 있습니다.)
  • 교차 출처 읽기는 보통 허용하지 않지만, 종종 교차 출처 삽입 과정에서 읽기 권한이 누출됩니다. 예를 들어 삽입된 이미지의 크기, 삽입된 스크립트의 작업, 또는 삽입된 리소스의 가용성을 읽을 수 있습니다.

다음은 교차 출처로 삽입할 수 있는 리소스의 일부 예시입니다.

  • <script src="…"></script>를 사용하는 JavaScript. 구문 오류에 대한 오류 세부 정보는 동일 출처 스크립트에서만 사용할 수 있습니다.
  • <link rel="stylesheet" href="…">로 적용된 CSS. CSS의 완화된 구문 규칙으로 인해 교차 출처 CSS에는 올바른 Content-Type 헤더가 요구됩니다. 브라우저는 MIME 유형이 올바르지 않고 리소스가 유효한 CSS 구성으로 시작하지 않는 교차 출처 로드인 경우 스타일시트 로드를 차단합니다.
  • <img>로 표시하는 이미지.
  • <video><audio> (en-US)로 재생하는 미디어.
  • <object><embed>로 삽입하는 외부 리소스.
  • @font-face로 적용하는 글꼴. 일부 브라우저는 교차 충처를 허용하지만, 다른 브라우드는 동일 출처를 요구할 수도 있습니다.
  • <iframe> (en-US)으로 삽입하는 모든 것. 사이트는 X-Frame-Options 헤더를 사용하여 출처 간 프레이밍을 방지할 수 있습니다.

교차 출처 접근을 허용하는 방법

CORS를 사용하여 교차 출처의 접근를 허용합니다. CORS는 서버가 브라우저에 콘텐츠 로드를 허용하는 다른 호스트를 지정할 수 있도록 하는 HTTP의 일부입니다.

교차 출처 접근을 막는 방법

  • 교차 출처 쓰기를 방지하려면 CSRF(Cross-Site Request Forgery) 토큰이라고 하는 요청에서 추측할 수 없는 토큰을 확인하십시오. 이 토큰이 필요한 페이지의 교차 출처 읽기를 막아야 합니다.
  • 리소스의 교차 출처 읽기를 방지하려면 리로스를 삽입 할 수 없도록 설정하세요. 리소스 삽입 과정에서 일부 정보가 새어 나가므로 삽입을 방지하는 경우가 많습니다.
  • 교차 출처 삽입을 방지하려면 리소스가 앞서 나열된 삽입 가능 형식 중 하나로 해석되지 않도록 해야 합니다. 브라우저는 Content-Type 헤더를 준수하지 않을 수 있습니다. 예를 들어 HTML 문서에서 <script> 태그를 가리키면 브라우저는 HTML을 JavaScript로 파싱려고합니다. 리소스가 사이트의 진입점이 아닌 경우 CSRF 토큰을 사용하여 삽입을 방지할 수도 있습니다.

교차 출처 스크립트 API 접근

iframe.contentWindow (en-US), window.parent (en-US), window.open (en-US), 그리고 window.opener와 같은 JavaScript API를 사용하면 문서가 서로를 직접 참조할 수 있습니다. 두 문서의 원본이 동일하지 않은 경우 이러한 참조는 다음 두 섹션에서 설명하는 것처럼 WindowLocation 객체에 대해 매우 제한된 액세스를 제공합니다.

서로 다른 출처의 문서간 통신을 하려면 window.postMessage를 사용하세요.

명세: HTML Living Standard § Cross-origin objects.

Window

다음 Window 속성에 대한 교차 출처 접근이 허용됩니다.

메서드
window.blur (en-US)
window.close (en-US)
window.focus (en-US)
window.postMessage
속성
window.closed 읽기 전용.
window.frames (en-US) 읽기 전용.
window.length 읽기 전용.
window.location 읽기/쓰기.
window.opener 읽기 전용.
window.parent (en-US) 읽기 전용.
window.self 읽기 전용.
window.top (en-US) 읽기 전용.
window.window (en-US) 읽기 전용.

일부 브라우저는 위의 항목보다 더 많은 접근을 허용할 수도 있습니다.

Location

다음 Location 속성에 대한 교차 출처 접근이 허용됩니다.

메서드
location.replace
속성
location.href (en-US) 쓰기 전용.

일부 브라우저는 위의 항목보다 더 많은 접근을 허용할 수도 있습니다.

교차 출처 데이터 저장소 접근

Web StorageIndexedDB와 같은 브라우저에 저장된 데이터에 대한 액세스는 출처별로 구분됩니다. 각 출처는 별도의 저장소를 가지며 한 출처의 JavaScript는 다른 출처에 속한 저장소에서 읽거나 쓸 수 없습니다.

쿠키는 출처에 대한 별도의 정의를 사용합니다. 페이지는 상위 도메인이 공개 접미사가 아닌 한 자체 도메인 또는 상위 도메인에 대한 쿠키를 설정할 수 있습니다. Firefox와 Chrome은 공개 접미사 목록을 사용하여 도메인이 공개 접미사인지 확인합니다. 쿠키를 설정할 때 Domain, Path, Secure, 그리고 HttpOnly 플래그를 사용하여 가용성을 제한할 수 있습니다. 쿠키를 읽을 때 쿠키가 어디에서 설정되었는지 알 수 없습니다. 안전한 https 연결만 사용하더라도 보이는 모든 쿠키는 안전하지 않은 연결을 사용하여 설정되었을 수 있습니다.

같이 보기