it-swarm.com.de

überprüfen Sie die anfragende URL

Mit WP 4.8.2

Wie kann die anfragende URL am besten überprüft werden, wenn eine Anfrage mit der Rest-API verarbeitet wird?

Beispielsweise erhält eine Site eine Anfrage und Sie möchten prüfen, ob diese von einer zulässigen URL stammt. Und scheitern, wenn die URL nicht erlaubt ist.

Das funktioniert nicht:

function my_check_request_url( $request, $url ) {

    $bits = parse_url( $url );

    if ( $bits['Host'] != 'example.com' )
       $request = false;

    return $request;

}
add_filter( 'rest_request_from_url', 'my_check_request_url', 10, 2 );
7
shanebp

Dieser Filter ist definitiv nicht der, den Sie suchen. Dieser Filter wird ausgelöst, bevor das Ergebnis von WP_REST_Request::from_url() zurückgegeben wird. Dies scheint eine Factory-Methode zu sein, die nur intern zur Verarbeitung von Einbettungen verwendet wird.

Eine bessere Option ist die Rückgabe einer WP_Error-Instanz im rest_pre_dispatch-Filter .

Einige Einschränkungen:

Wie von @milo erwähnt, ist der Referer nicht zuverlässig und sollte nicht für eine Sicherheitskontrolle verwendet werden.

Darüber hinaus wird nicht garantiert, dass es festgelegt wird.

Nachstehend finden Sie ein Beispiel dafür, wie Sie den rest_pre_dispatch-Filter verwenden können, um die Anforderung fehlschlagen zu lassen, wenn sie von einem fehlerhaften Verweis stammt:

function wpse281916_rest_check_referer( $result, $server, $request ) {
    if ( null !== $result ) {
        // Core starts with a null value.
        // If it is no longer null, another callback has claimed this request.
        // Up to you how to handle - for this example we will just return early.
        return $result;
    }

    $referer = $request->get_header( 'referer' );

    if ( ! $referer ) {
        // Referer header is not set - If referer is required, return a WP_Error instance instead.
        return $result;
    }

    $Host = wp_parse_url( $referer, PHP_URL_Host );

    if ( ! $Host ) {
        // Referer is malformed - If referer is required, return a WP_Error instance instead.
        return $result;
    }

    if ( 'mysite.com' !== $Host ) {
        // Referer is set to something that we don't allow.
        return new WP_Error(
            'invalid-referer',
            'Requests must contain a valid referer',
            compact( 'referer' )
        );
    }

    // Otherwise we are good - return original result and let WordPress handle as usual.
    return $result;
}
add_filter( 'rest_pre_dispatch', 'wpse281916_rest_check_referer', 10, 3 );
5
ssnepenthe

Alles, was Sie vom Client erhalten, wird als Benutzereingabe betrachtet und sollte nicht als vertrauenswürdig eingestuft werden. Da der Header leicht manipuliert und missbraucht werden kann, rate ich davon ab, diese Methode zu verwenden, wenn Sie sich bei vertraulichen Daten darauf verlassen.

Wenn die Anforderungen von einer Seite stammen, können Sie einen anderen Ansatz wählen. Andernfalls kann jeder eine Anfrage an die API senden und den Referrer ändern.

Angenommen, Sie haben eine Reihe von Seiten, die als "Zulässig" gefiltert sind. Sie können nur für diese Seiten eine Ankündigung erstellen und sie dann in Ihrer Anfrage validieren.

Wenn eine Nounce existiert und gültig ist, ist die Anfrage erlaubt. Ansonsten blockiere es.

4
Jack Johansson

@ssnepenthe 's aswer sagt zu Recht, dass der Hook, den Sie verwenden, nicht der richtige in einer eingehenden Anfrage ist.

Anforderungsinformationen sind für PHP sofort verfügbar, sodass Sie den frühesten verfügbaren Hook verwenden können, um sie zu überprüfen. Und wenn Sie dies im Kontext der Anforderungs-API tun möchten, sollten Sie den frühesten Hook einer REST-API-Anforderung verwenden. Der von @ssnepenthe vorgeschlagene 'rest_pre_dispatch' ist in Ordnung. Eine andere Option könnte sein rest_authentication_errors , mit der Sie einen Fehler zurückgeben können, falls etwas nicht stimmt.

Aber Jack Johansson hat Recht damit, zu sagen dass HTTP-Header (wie der in @ ssnepenthes aswer verwendete Referer-Header) nicht vertrauenswürdig sind, da sie vom Client sehr leicht geändert werden können. Es wäre also so, als würde man einen Wachmann vor eine Tür stellen, der nur fragt: "Es ist sicher, Sie eintreten zu lassen?" an alle, die reingehen wollen: das wird nicht funktionieren.

Aber die von Jack Johansson vorgeschlagene Lösung (ein Nonce) ist auch keine echte Lösung: Der springende Punkt bei Nonces ist, sich mit der Zeit zu ändern, und ein öffentlicher API-Endpunkt kann keine Dinge haben, die sich auf der Grundlage der Zeit ändern. Darüber hinaus sind WP Nonces nur dann vertrauenswürdig, wenn ein angemeldeter Benutzer vorhanden ist, was bei einer öffentlichen API möglicherweise nicht der Fall ist. Wenn ein Benutzer angemeldet ist, gibt es wahrscheinlich keinen Grund, die eingehende Domäne zu überprüfen: Sie Vertrauen Sie dem Benutzer, nicht dem Computer des Benutzers.

Also, was ist zu tun?

Nun, auch wenn HTTP-Header nicht vertrauenswürdig sind, stammen nicht alle auf $_SERVER verfügbaren Informationen aus Headern.

Normalerweise stammen alle $_SERVER-Werte, deren Schlüssel mit HTTP_ beginnen, aus Kopfzeilen und müssen als unsichere Benutzereingabe behandelt werden.

Beispiel: $_SERVER['REMOTE_ADDR'] enthält die IP-Adresse, die für die Verbindung von TCP zu Ihrem Server verwendet wird. Dies bedeutet, dassvertrauenswürdig ist1.

Was auch bedeutet, dass entweder:

  • richtige Konfiguration des Servers zur Generierung des $_SERVER['REMOTE_Host']-Werts (in Apache benötigen Sie beispielsweise HostnameLookups On in Ihrem httpd.conf)
  • verwenden von gethostbyaddr , um eine umgekehrte DNS-Suche durchzuführen, um den Domänennamen der in $_SERVER['REMOTE_ADDR'] gespeicherten IP aufzulösen.

sie könnten ziemlich zuverlässig einen Hostnamen erhalten, mit dem Sie gegen eine Whitelist prüfen könnten (für den Code könnten Sie den Code von @ ssnepenthe's aswer anpassen, wo Sie $referer = $request->get_header('referer') durch $referer = gethostbyaddr($_SERVER['REMOTE_ADDR']) ersetzen würden).

Aber es gibt ein Problem .

Befindet sich Ihr Webserver hinter einem Reverse-Proxy (eigentlich eine recht gebräuchliche Lösung), wird die TCP -Verbindung zum Webserver tatsächlich vom Proxy hergestellt. Daher ist $_SERVER['REMOTE_ADDR'] die IP des Proxys und nicht die IP des Client, der die Anfrage ursprünglich gesendet hat.

Die ursprüngliche Anforderungs-IP ist in solchen Fällen normalerweise als $_SERVER['HTTP_X_FORWARDED_FOR'] verfügbar, aber als einer dieser $_SERVER-Werte, die mit HTTP_ beginnen, ist sie nicht wirklich vertrauenswürdig.

Wenn sich Ihr Webserver also hinter einem Reverse-Proxy befindet2 Selbst der $_SERVER['REMOTE_ADDR'] wäre für einen solchen Schutz nicht nützlich, und eine domänenbasierte Whitelist könnte nur auf Proxy-Ebene implementiert werden.

Kurz gesagt, eine zuverlässige Lösung für die API-Endpunktsicherung sollte entweder mithilfe eines real -Authentifizierungsmechanismus (z. B. oAuth) implementiert werden oder direkt auf der Serverkonfiguration und nicht auf Anwendungsebene ausgeführt werden.


Anmerkungen

1 Nun, theoretisch könnte es kaputt gehen, wenn jemand Ihren ISP hackt oder wenn ein Angreifer in Ihrem LAN agiert. In beiden Fällen gibt es nur sehr wenig, was Sie tun können, um sicher zu gehen.

2 Wenn Sie nicht wissen, ob Sie sich hinter einem Reverse-Proxy befinden, können Sie eine Anfrage von Ihrem lokalen PC senden und prüfen, ob $_SERVER['REMOTE_ADDR'] auf dem Server mit der lokalen PC-IP übereinstimmt und ob $_SERVER['HTTP_X_FORWARDED_FOR'] vorhanden ist und mit der lokalen PC-IP übereinstimmt.

4
gmazzap