Same-Origin-Policy
Die Same-Origin-Policy ist ein kritischer Sicherheitsmechanismus, der einschränkt, wie ein Dokument oder Skript, das von einem Ursprung geladen wird, mit einer Ressource von einem anderen Ursprung interagieren kann.
Er hilft, potenziell schädliche Dokumente zu isolieren und mögliche Angriffspunkte zu reduzieren. Zum Beispiel verhindert er, dass eine bösartige Website im Internet JavaScript in einem Browser ausführt, um Daten von einem Drittanbieter-Webmail-Dienst (bei dem der Benutzer angemeldet ist) oder einem Unternehmens-Intranet (das vor direktem Zugriff durch den Angreifer geschützt ist, da es keine öffentliche IP-Adresse hat) zu lesen und diese Daten an den Angreifer weiterzuleiten.
Definition eines Ursprungs
Zwei URLs haben denselben Ursprung, wenn das Protokoll, der Port (falls angegeben) und der Host für beide gleich sind. Dies wird oft als "Schema/Host/Port-Tupel" oder einfach "Tupel" bezeichnet. (Ein "Tupel" ist eine Menge von Elementen, die zusammen ein Ganzes bilden — eine generische Form für Doppel/Dreifach/Vierfach/Fünffach/usw.)
Die folgende Tabelle gibt Beispiele für Ursprungsvergleiche mit der URL http://store.company.com/dir/page.html
:
URL | Ergebnis | Grund |
---|---|---|
http://store.company.com/dir2/other.html |
Gleicher Ursprung | Nur der Pfad unterscheidet sich |
http://store.company.com/dir/inner/another.html |
Gleicher Ursprung | Nur der Pfad unterscheidet sich |
https://store.company.com/page.html |
Fehler | Unterschiedliches Protokoll |
http://store.company.com:81/dir/page.html |
Fehler | Unterschiedlicher Port (http:// ist standardmäßig Port 80) |
http://news.company.com/dir/page.html |
Fehler | Unterschiedlicher Host |
Geerbte Ursprünge
Von Seiten mit einer about:blank
oder javascript:
URL ausgeführte Skripte erben den Ursprung des Dokuments, das diese URL enthält, da diese Arten von URLs keine Informationen über einen Ursprungsserver enthalten.
Zum Beispiel wird about:blank
oft als URL für neue, leere Popup-Fenster verwendet, in die das übergeordnete Skript Inhalte schreibt (z. B. über den Mechanismus Window.open()
). Wenn dieses Popup ebenfalls JavaScript enthält, würde dieses Skript denselben Ursprung erben wie das Skript, das es erstellt hat.
data:
URLs erhalten einen neuen, leeren Sicherheitskontext.
Dateiorsprünge
Moderne Browser behandeln den Ursprung von Dateien, die mit dem file:///
-Schema geladen wurden, normalerweise als undurchsichtige Ursprünge.
Das bedeutet, dass wenn eine Datei andere Dateien aus demselben Ordner (zum Beispiel) einbezieht, sie nicht als vom selben Ursprung kommend angesehen werden, und es können CORS-Fehler auftreten.
Zu beachten ist, dass die URL-Spezifikation besagt, dass der Ursprung von Dateien implementierungsabhängig ist, und einige Browser können Dateien im selben Verzeichnis oder Unterverzeichnis als gleichen Ursprung behandeln, obwohl dies Sicherheitsimplikationen hat.
Ursprung ändern
Warnung:
Die hier beschriebene Vorgehensweise (Verwendung des document.domain
Setters) ist veraltet, da sie die von der Same-Origin-Policy bereitgestellten Sicherheitsmaßnahmen untergräbt und das Ursprungsmodell in Browsern kompliziert, was zu Interoperabilitätsproblemen und Sicherheitsfehlern führt.
Eine Seite kann ihren eigenen Ursprung ändern, mit einigen Einschränkungen. Ein Skript kann den Wert von document.domain
auf seine aktuelle Domain oder eine Überdomain seiner aktuellen Domain setzen. Wenn es auf eine Überdomain der aktuellen Domain gesetzt wird, wird die kürzere Überdomain für Same-Origin-Überprüfungen verwendet.
Zum Beispiel, nehmen wir an, ein Skript aus dem Dokument unter http://store.company.com/dir/other.html
führt folgendes aus:
document.domain = "company.com";
Danach kann die Seite die Same-Origin-Überprüfung mit http://company.com/dir/page.html
bestehen (vorausgesetzt, http://company.com/dir/page.html
setzt sein document.domain
auf "company.com"
, um anzugeben, dass dies erlaubt werden soll - siehe document.domain
für mehr). company.com
könnte jedoch nicht document.domain
auf othercompany.com
setzen, da dies keine Überdomain von company.com
ist.
Die Portnummer wird von dem Browser separat überprüft. Jeder Aufruf von document.domain
, einschließlich document.domain = document.domain
, überschreibt die Portnummer mit null
. Daher kann man nicht company.com:8080
nur durch das Setzen von document.domain = "company.com"
im ersten Fall mit company.com
sprechen lassen. Es muss in beiden gesetzt sein, damit ihre Portnummern beide null
sind.
Der Mechanismus hat einige Einschränkungen. Zum Beispiel, er wirft einen SecurityError
DOMException
, wenn die document-domain
Permissions-Policy
aktiviert ist oder das Dokument in einem sandboxed <iframe>
ist, und das Ändern des Ursprungs auf diese Weise beeinflusst nicht die von vielen Web-APIs verwendeten Ursprungschecks (z. B. localStorage
, indexedDB
, BroadcastChannel
, SharedWorker
). Eine umfassendere Liste von Fehlerfällen finden Sie in Document.domain > Failures.
Hinweis:
Wenn Sie document.domain
verwenden, um einem Subdomain den Zugriff auf seine übergeordnete Domain zu gewähren, müssen Sie document.domain
auf denselben Wert sowohl in der übergeordneten Domain als auch in der Subdomain setzen. Dies ist notwendig, selbst wenn durch das Zurücksetzen der übergeordneten Domain auf ihren ursprünglichen Wert. Wenn Sie dies nicht tun, können Berechtigungsfehler auftreten.
Netzwerkzugriff zwischen unterschiedlichen Ursprüngen
Die Same-Origin-Policy steuert Interaktionen zwischen zwei unterschiedlichen Ursprüngen, wie beim Verwenden von fetch()
oder einem <img>
-Element. Diese Interaktionen werden typischerweise in drei Kategorien unterteilt:
- Schreiben zwischen Ursprüngen ist typischerweise erlaubt. Beispiele sind Links, Weiterleitungen und Formularübermittlungen. Einige HTTP-Anfragen erfordern eine Preflight.
- Einbetten zwischen Ursprüngen ist typischerweise erlaubt. (Beispiele sind unten aufgeführt.)
- Lesen zwischen Ursprüngen ist typischerweise nicht erlaubt, aber der Lesezugriff wird häufig durch Einbettung geleakt. Zum Beispiel können Sie die Dimensionen eines eingebetteten Bildes, die Aktionen eines eingebetteten Skripts oder die Verfügbarkeit einer eingebetteten Ressource lesen.
Hier sind einige Beispiele für Ressourcen, die über Ursprünge hinweg eingebettet werden können:
- JavaScript mit
<script src="…"></script>
. Fehlerdetails für Syntaxfehler sind nur für Skripte des gleichen Ursprungs verfügbar. - CSS, angewandt mit
<link rel="stylesheet" href="…">
. Aufgrund der entspannten Syntaxregeln von CSS erfordert CSS zwischen Ursprüngen einen korrektenContent-Type
-Header. Browser blockieren das Laden von Stylesheets, wenn es sich um ein Laden zwischen Ursprüngen handelt, bei dem der MIME-Typ falsch ist und die Ressource nicht mit einem gültigen CSS-Konstrukt beginnt. - Bilder, die durch
<img>
angezeigt werden. - Medien, die durch
<video>
und<audio>
abgespielt werden. - Externe Ressourcen, die mit
<object>
und<embed>
eingebettet werden. - Schriften, die mit
@font-face
angewendet werden. Einige Browser erlauben Schriften zwischen Ursprüngen, andere erfordern den gleichen Ursprung. - Alles, was durch
<iframe>
eingebettet wird. Websites können denX-Frame-Options
-Header verwenden, um die Einbettung über Ursprünge hinweg zu verhindern.
Wie man Zugriff über Ursprünge erlaubt
Wie man Zugriff über Ursprünge blockiert
- Um Schreiben zwischen Ursprüngen zu verhindern, überprüfen Sie ein unvorhersehbares Token in der Anfrage — bekannt als Cross-Site Request Forgery (CSRF)-Token. Sie müssen das Lesen von Seiten verhindern, die dieses Token erfordern.
- Um das Lesen zwischen Ursprüngen einer Ressource zu verhindern, stellen Sie sicher, dass sie nicht einbettbar ist. Es ist oft notwendig, das Einbetten zu verhindern, da das Einbetten einer Ressource immer einige Informationen darüber leakt.
- Um das Einbetten zwischen Ursprüngen zu verhindern, stellen Sie sicher, dass Ihre Ressource nicht als eines der oben aufgeführten einbettbaren Formate interpretiert werden kann. Browser respektieren möglicherweise nicht den
Content-Type
-Header. Zum Beispiel, wenn Sie ein<script>
-Tag auf ein HTML-Dokument verweisen, wird der Browser versuchen, das HTML als JavaScript zu parsen. Wenn Ihre Ressource kein Einstiegspunkt Ihrer Website ist, können Sie auch ein CSRF-Token verwenden, um das Einbetten zu verhindern.
Skript-API-Zugriff zwischen Ursprüngen
JavaScript-APIs wie iframe.contentWindow
, window.parent
, window.open
und window.opener
erlauben es Dokumenten, sich direkt aufeinander zu beziehen. Wenn zwei Dokumente nicht denselben Ursprung haben, bieten diese Referenzen nur begrenzten Zugriff auf Window
- und Location
-Objekte, wie in den nächsten beiden Abschnitten beschrieben.
Um zwischen Dokumenten von unterschiedlichen Ursprüngen zu kommunizieren, verwenden Sie window.postMessage
.
Spezifikation: HTML Living Standard § Cross-origin objects.
Window
Folgender Zugriff auf Window
-Eigenschaften zwischen Ursprüngen ist erlaubt:
Attribute | |
---|---|
window.closed |
Nur lesbar. |
window.frames |
Nur lesbar. |
window.length |
Nur lesbar. |
window.location |
Lesen/Schreiben. |
window.opener |
Nur lesbar. |
window.parent |
Nur lesbar. |
window.self |
Nur lesbar. |
window.top |
Nur lesbar. |
window.window |
Nur lesbar. |
Einige Browser erlauben den Zugriff auf mehr Eigenschaften als die oben genannten.
Location
Folgender Zugriff auf Location
-Eigenschaften zwischen Ursprüngen ist erlaubt:
Methoden |
---|
location.replace |
Attribute | |
---|---|
location.href |
Schreibgeschützt. |
Einige Browser erlauben den Zugriff auf mehr Eigenschaften als die oben genannten.
Datenzugriff über Ursprünge hinweg
Der Zugriff auf im Browser gespeicherte Daten wie Web Storage und IndexedDB wird nach Ursprung getrennt. Jeder Ursprung erhält seinen eigenen separaten Speicher, und JavaScript in einem Ursprung kann nicht in den Speicher eines anderen Ursprungs lesen oder schreiben.
Cookies verwenden eine separate Definition von Ursprüngen. Eine Seite kann ein Cookie für ihre eigene Domain oder eine übergeordnete Domain setzen, solange die übergeordnete Domain nicht ein öffentlicher Suffix ist. Firefox und Chrome verwenden die Public Suffix List, um zu bestimmen, ob eine Domain ein öffentlicher Suffix ist. Wenn Sie ein Cookie setzen, können Sie seine Verfügbarkeit mit den Domain
, Path
, Secure
, und HttpOnly
-Flags begrenzen. Wenn Sie ein Cookie lesen, können Sie nicht sehen, von wo es gesetzt wurde. Selbst wenn Sie nur sichere https-Verbindungen verwenden, kann jedes Cookie, das Sie sehen, über eine unsichere Verbindung gesetzt worden sein.