Wie kann man Access-Control-Allow-Origin umgehen?

196

Ich mache einen Ajax-Aufruf an meinen eigenen Server auf einer von ihnen festgelegten Plattform, um diese Ajax-Aufrufe zu verhindern (aber ich brauche ihn, um die Daten von meinem Server abzurufen und die abgerufenen Daten aus der Datenbank meines Servers anzuzeigen). Mein Ajax-Skript funktioniert. Es kann die Daten an das PHP-Skript meines Servers senden, damit es verarbeitet werden kann. Die verarbeiteten Daten können jedoch nicht zurückerhalten werden, da sie von blockiert werden"Access-Control-Allow-Origin"

Ich habe keinen Zugriff auf die Quelle / den Kern dieser Plattform. Daher kann ich das Skript nicht entfernen, das es mir nicht erlaubt. (P / SI hat die Google Chrome-Konsole verwendet und diesen Fehler festgestellt.)

Der Ajax-Code wie unten gezeigt:

 $.ajax({
     type: "GET",
     url: "http://example.com/retrieve.php",
     data: "id=" + id + "&url=" + url,
     dataType: 'json',   
     cache: false,
     success: function(data)
      {
        var friend = data[1];              
        var blog = data[2];           
        $('#user').html("<b>Friends: </b>"+friend+"<b><br> Blogs: </b>"+blog);

      } 
  });

oder gibt es einen JSONäquivalenten Code zum obigen Ajax-Skript? Ich denke JSONist erlaubt.

Ich hoffe jemand konnte mir helfen.

ETAN
quelle
In allen bisherigen Antworten auf Ihre Frage wurde erläutert, wie Sie Ihren Servercode neu schreiben können, damit Ajax funktioniert. Bei keinem von ihnen geht es um das Umgehen, wie Sie in Ihrer Frage speziell gefragt haben. Haben Sie trotzdem gefunden, diesen Header tatsächlich zu umgehen? Ich bezweifle wirklich, dass es einen geben würde.
Moradnejad
Es gibt keine Möglichkeit, es zu umgehen. Sie können jedoch eine Datei in Ihr Backend einfügen, die die Anforderung ausführt. Sie rufen also per Ajax die Datei auf Ihrem eigenen Server auf, diese Datei lädt die Daten aus retrieve.php und sendet sie zurück an Ihr Javascript. In diesem Fall gibt es keine CORS-Regeln, die Sie blockieren.
Jona Paulus

Antworten:

365

Setzen Sie dies oben auf retrieve.php:

header('Access-Control-Allow-Origin: *');  

Beachten Sie, dass dadurch der CORS-Schutz effektiv deaktiviert wird und Ihre Benutzer Angriffen ausgesetzt sind. Wenn Sie nicht ganz sicher sind, ob Sie alle Ursprünge zulassen müssen , sollten Sie dies auf einen genaueren Ursprung beschränken:

header('Access-Control-Allow-Origin: https://www.example.com')

Weitere Informationen finden Sie in der folgenden Stapelantwort Access-Control-Allow-Origin

https://stackoverflow.com/a/10636765/413670

Rafay
quelle
54
Das ist ziemlich unsicher. Schauen Sie sich meine Antwort unten an.
Rob
3
tnx, aber Sie sollten nicht den Zugriff auf alle Ursprünge erlauben, wie von @RobQuist in seinem Kommentar erwähnt, und in seiner Antwort lieferte einen besseren Ansatz
Rafay
2
Ich habe diese Seite gefunden, weil ich die Zugriffssteuerung auf einem Server tatsächlich umgehen musste. Die Lösung hier umgeht nichts, sondern konfiguriert die Zugriffssteuerung einfach richtig auf seinem eigenen Server. Falls jemand da draußen dies tatsächlich umgehen muss, kann er PHPs file_get_contents ($ remote_url); verwenden. Es gibt offensichtlich viele Möglichkeiten, dies zu tun, aber so habe ich es gemacht.
Shawn Whinnery
1
@ShawnWhinnery, das ist im Grunde der Akt des "Proxying". Gute Lösung, wenn Sie wirklich dynamisch Daten von einer anderen Website laden möchten, auf die Sie keinen Einfluss haben.
Rob
1
wollte PHP-Skript vom Dotnet-Kern ausführen - PHP-Skript wurde auf meine andere URL verschoben, es wurde jedoch ein Fehler beim Cross-Site-Scripting angezeigt. fügte den Code, den Sie gezeigt haben, zu PHP hinzu und funktionierte perfekt. Vielen Dank!
Raddevus
290

Okay, aber Sie alle wissen, dass das * ein Platzhalter ist und Cross-Site-Scripting von jeder Domain aus ermöglicht?

Sie möchten Access-Control-Allow-Originfür jede Site, die dazu berechtigt ist, mehrere Access-Control-Allow-OriginHeader senden. Leider wird das Senden mehrerer Header oder das Einfügen mehrerer Ursprünge offiziell nicht unterstützt .

Sie können dies lösen, indem Sie den Ursprung überprüfen und diesen in der Kopfzeile zurücksenden, sofern dies zulässig ist:

$origin = $_SERVER['HTTP_ORIGIN'];
$allowed_domains = [
    'http://mysite1.com',
    'https://www.mysite2.com',
    'http://www.mysite2.com',
];

if (in_array($origin, $allowed_domains)) {
    header('Access-Control-Allow-Origin: ' . $origin);
}

Das ist viel sicherer. Möglicherweise möchten Sie die Übereinstimmung bearbeiten und in eine manuelle Funktion mit einem regulären Ausdruck oder Ähnlichem ändern. Zumindest wird dadurch nur 1 Header zurückgesendet, und Sie werden sicher sein, dass es derjenige ist, von dem die Anfrage kam. Bitte beachten Sie, dass alle HTTP - Header können gefälscht sein, aber dieser Header ist für den Schutz des Kunden. Schützen Sie Ihre eigenen Daten nicht mit diesen Werten. Wenn Sie mehr wissen möchten, lesen Sie etwas über CORS und CSRF.

Warum ist es sicherer?

Wenn Sie den Zugriff von anderen Standorten als Ihrer eigenen vertrauenswürdigen Site aus zulassen, können Sie Sitzungs-Highjacking durchführen. Ich werde mit einem kleinen Beispiel beginnen - Bild Facebook erlaubt einen Platzhalter-Ursprung - dies bedeutet, dass Sie Ihre eigene Website irgendwo erstellen und AJAX-Aufrufe (oder offene Iframes) an Facebook auslösen können. Dies bedeutet, dass Sie die angemeldeten Informationen auf Facebook eines Besuchers Ihrer Website abrufen können. Schlimmer noch - Sie können POSTAnfragen per Skript schreiben und Daten auf Facebook veröffentlichen - nur während diese auf Ihrer Website surfen.

Seien Sie sehr vorsichtig, wenn Sie die ACAOHeader verwenden!

rauben
quelle
12
Ich denke, Sie müssen http: // vor jedes Element in der Liste setzen. Zumindest für eine Site, an der ich gearbeitet habe.
Blak3r
2
Leider scheint das nicht zu funktionieren. Ich glaube, dass nur eine Ausnahme pro Aufruf von header () bereitgestellt werden kann.
lewsid
5
@Shanimal & lewsid -> Ich denke, Komma getrennt funktioniert in der Tat nicht. Referenz: w3.org/TR/cors
Rob
3
Für den Umgang mit einer Liste von Domains hier eine relevante Antwort: stackoverflow.com/a/1850482/766177
Valentin Despa
13
Dies ist sinnlos, wenn Sie 4 solcher Header hinzufügen, da jeder Aufruf header()den vorherigen Header desselben Typs ersetzt. Sie setzen also wirklich nur den letzten Header. Der manuelle Eintrag besagt, dass Sie einen zweiten Parameter von festlegen können, um falsezu verhindern, dass der vorherige Header überschrieben wird.
BadHorsie
31

Warnung , Chrome (und andere Browser) beschweren sich, dass mehrere ACAO-Header festgelegt sind, wenn Sie einigen der anderen Antworten folgen.

Der Fehler wird so etwas wie sein XMLHttpRequest cannot load ____. The 'Access-Control-Allow-Origin' header contains multiple values '____, ____, ____', but only one is allowed. Origin '____' is therefore not allowed access.

Versuche dies:

$http_origin = $_SERVER['HTTP_ORIGIN'];

$allowed_domains = array(
  'http://domain1.com',
  'http://domain2.com',
);

if (in_array($http_origin, $allowed_domains))
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

quelle
6
Dies ist eine noch bessere Lösung als die, die ich gepostet habe.
Rob
7

Ich habe dieses Problem beim Aufrufen eines MVC3-Controllers behoben. Ich fügte hinzu:

Response.AddHeader("Access-Control-Allow-Origin", "*"); 

vor meinem

return Json(model, JsonRequestBehavior.AllowGet);

Außerdem habe ich mich $.ajaxdarüber beschwert, dass in meinem Ajax-Aufruf kein Header vom Typ Inhalt akzeptiert wird. Deshalb habe ich ihn auskommentiert, da ich weiß, dass sein JSON an die Aktion übergeben wird.

Hoffentlich hilft das.

Atif Rehman
quelle
2

Es ist eine wirklich schlechte Idee *, die Sie für Cross-Site-Scripting offen lässt. Grundsätzlich möchten Sie ständig Ihre eigene Domain, die auf Ihre aktuellen SSL-Einstellungen und optional zusätzliche Domains beschränkt ist. Sie möchten auch, dass alle als ein Header gesendet werden. Im Folgenden wird immer Ihre eigene Domain im selben SSL-Bereich wie die aktuelle Seite autorisiert und kann optional auch eine beliebige Anzahl zusätzlicher Domains enthalten. Sie werden alle als ein Header gesendet und die vorherigen überschrieben, wenn sie bereits von einem anderen gesendet wurden, um zu verhindern, dass der Browser über das Senden mehrerer Header für die Zugriffssteuerung meckert.

class CorsAccessControl
{
    private $allowed = array();

    /**
     * Always adds your own domain with the current ssl settings.
     */
    public function __construct()
    {
        // Add your own domain, with respect to the current SSL settings.
        $this->allowed[] = 'http'
            . ( ( array_key_exists( 'HTTPS', $_SERVER )
                && $_SERVER['HTTPS'] 
                && strtolower( $_SERVER['HTTPS'] ) !== 'off' ) 
                    ? 's' 
                    : null )
            . '://' . $_SERVER['HTTP_HOST'];
    }

    /**
     * Optionally add additional domains. Each is only added one time.
     */
    public function add($domain)
    {
        if ( !in_array( $domain, $this->allowed )
        {
            $this->allowed[] = $domain;
        }
    /**
     * Send 'em all as one header so no browsers grumble about it.
     */
    public function send()
    {
        $domains = implode( ', ', $this->allowed );
        header( 'Access-Control-Allow-Origin: ' . $domains, true ); // We want to send them all as one shot, so replace should be true here.
    }
}

Verwendung:

$cors = new CorsAccessControl();

// If you are only authorizing your own domain:
$cors->send();

// If you are authorizing multiple domains:
foreach ($domains as $domain)
{
    $cors->add($domain);
}
$cors->send();

Du hast die Idee.

Mopsyd
quelle
1

Haben Sie versucht, der von Ihrem Server gesendeten Antwort tatsächlich den Header Access-Control-Allow-Origin hinzuzufügen? Wie Access-Control-Allow-Origin: *?

Daniel Brockman
quelle
1
Es ist ein HTTP-Header, den Ihr Server sendet, um den Browser darüber zu informieren, dass es in Ordnung ist, das Ergebnis dem aufrufenden Skript anzuzeigen, obwohl die Ursprungsdomäne des Skripts nicht mit der Domäne des Servers übereinstimmt. Informieren Sie sich über Cross-Origin Resource Sharing !
Daniel Brockman