リクエストしているURLを確認する


9

WP 4.8.2の使用

rest-apiでリクエストを処理するときにリクエストURLを確認する最良の方法は何ですか?

たとえば、サイトがリクエストを受け取り、それが「許可された」URLからのものであるかどうかを確認したいとします。URLが許可されていない場合は失敗します。

これは動作しません:

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 );

条件をコメント化した後も、応答は送信されます。だから私は間違ったフックを使用していると思います。
shanebp 2017年

あなたは何をチェックしてい$request$url経由のような外観をvarsのvar_dump私は、入力と出力を検査することは、常に適切な答えにつながることがわかり、または類似しました。
farinspace 2017年

2
参照URLは簡単に偽造され、あらゆる種類のセキュリティには使用できません。
Milo

トークンとSSLを使用しています。また、偽造の可能性があるかどうかに関係なく、参照URLを確認したいと思います。
shanebp 2017年

2
これはWebに公開されているAPIであり、認証とSSLは関係がないとして、審判員についてこの話は何ですか。CORS保護も無効にしている可能性があります...ログインしているユーザーだけが使用できる場合を除き、セキュリティはゼロです。
マークカプルン2017年

回答:


5

そのフィルターは間違いなくあなたが探しているものではありません。そのフィルタは、WP_REST_Request::from_url()埋め込みを処理するために内部的にのみ使用されるファクトリメソッドのように見える結果を返す前に起動します。

より良いオプションはWP_Errorrest_pre_dispatchフィルターのインスタンスを返すことです。

いくつかの警告:

@miloで述べたように、リファラーは信頼性が高くないため、セキュリティチェックに使用しないでください。

また、設定される保証はありません。

それらが邪魔にrest_pre_dispatchならない場合、以下は、不適切なリファラーからのリクエストである場合にフィルターを使用してリクエストを失敗させる方法の例です。

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 );

4

クライアントから受け取るものはすべてユーザー入力と見なされ、信頼すべきではありません。ヘッダーは簡単に操作および悪用される可能性があるため、機密データについてヘッダーに依存している場合は、この方法を使用しないことをお勧めします。

リクエストがページからのものである場合は、別のアプローチをとることができます。それ以外の場合、誰もがどこからでもAPIにリクエストを送信してリファラーを変更できます。

「許可」としてフィルターされた一連のページがあるとします。これらのページに対してのみ通知を作成し、リクエストでそれらを検証できます。

通知が存在し、それが有効な場合、要求は許可されます。それ以外の場合は、ブロックします。


4
+1 ...これはAPIです....ブラウザーからのみ呼び出しを取得するという仮定はばかげています。
マークカプルン2017年

はい、nounceは、誰かが直接APIにリクエストを送信する場合には存在しないため、より良いアプローチだと思います。
ジャックヨハンソン

4

@ssnepentheの回答は、あなたが使用しているフックが着信リクエストの中で何か正しいものではないと言っているのは正しいです。

リクエスト情報はPHPですぐに利用できるため、利用可能な最も古いフックを使用してそれらをチェックできます。リクエストAPIのコンテキストでこれを行う場合は、REST APIリクエストの最も早いフックを使用する必要があります。@ssnepenthe'rest_pre_dispatch'によって提案された問題はありませんが、別のオプションが考えられますrest_authentication_errors、何か問題が発生した場合にエラーを返すことができるられます。

しかし、ジャック・ヨハンソンは右であると言って、彼らは非常に簡単にクライアントによって変更されるHTTPヘッダー(@ ssnepentheのaswerで使用Refererヘッダなど)は、信頼できるではないこと。つまり、ドアの前に「入場しても安全ですか?」と尋ねる警備員を置くようなものです。行きたい人には:それはうまくいきません。

しかし、Jack Johanssonの回答(ノンス)が提案する解決策も実際の解決策ではありません。ノンスの要点は時間とともに変化することであり、パブリックAPIエンドポイントは時間に基づいて変化するものを持つことができません。さらに、WPナンスは、ログインしているユーザーがいる場合にのみ信頼できます。これは、パブリックAPIの場合とは異なり、ユーザーがログインしている場合、受信ドメインを確認する理由はおそらくありません。ユーザーではなくユーザーを信頼します。ユーザーマシン。

じゃあ何をすればいいの?

まあ、HTTPヘッダーが信頼できない場合でも、利用可能なすべての情報がヘッダーから得られるわけではありません$_SERVER

通常、$_SERVERキーで始まるすべての値HTTP_はヘッダーから取得され、安全でないユーザー入力として処理する必要があります

しかし、例えば、$_SERVER['REMOTE_ADDR']それがどの手段、サーバーへのTCP接続に使用するIPアドレスが含まれている信頼できる1

つまり、次のいずれかです。

  • $_SERVER['REMOTE_HOST']値を生成するようにサーバーを適切に構成する(たとえば、Apache では、HostnameLookups On内部で必要になりますhttpd.conf)その値
  • gethostbyaddr格納されているIPのドメイン名を解決するために逆DNSルックアップを実行するために使用$_SERVER['REMOTE_ADDR']

ホワイトリストに照らして確認するために使用できるホスト名を確実に取得できます(コードの場合、@ ssnepentheの質問に置き換え$referer = $request->get_header('referer')て、コードをに置き換えます$referer = gethostbyaddr($_SERVER['REMOTE_ADDR']))。

しかし、問題があります。

Webサーバーがリバースプロキシの背後にある場合(実際には非常に一般的なソリューション)、WebサーバーへのTCP接続は実際にはプロキシによって行われるため$_SERVER['REMOTE_ADDR']、最初に要求を送信したクライアントのIPではなく、プロキシのIPになります。

そのような場合の元のリクエストIPは通常として利用できますが$_SERVER['HTTP_X_FORWARDED_FOR']、それ$_SERVERで始まる値の1つであるHTTP_ことは、実際には信頼できません。

したがって、ウェブサーバーがリバースプロキシ2の背後にある場合でも、$_SERVER['REMOTE_ADDR']そのようなガードには役立ちません。ドメインベースのホワイトリストは、プロキシレベルでのみ実装できます。

つまり、APIエンドポイントのセキュリティ保護のための信頼できるソリューションは、実際の認証メカニズム(oAuthなど)を使用して実装するか、アプリケーションレベルではなくサーバー構成に直接作用して実行する必要があります。


ノート

1まあ、理論的には、誰かがあなたのISPをハッキングしたり、攻撃者があなたのLANの内側から行動したりすると、破壊される可能性があります。どちらの場合も、安全のためにできることはほとんどありません。

2リバースプロキシの背後にあるかどうかわからない場合は、ローカルPCからリクエストを送信$_SERVER['REMOTE_ADDR']し、サーバー上でローカルPCのIPと$_SERVER['HTTP_X_FORWARDED_FOR']一致するかどうか、また存在していてローカルPCのIPと一致するかどうかを確認できます。


OPはリファラーを取得しようとしているので、APIに直接pingするのではなく、ページ上でそれを実行したいと思いました。
ジャックヨハンソン

@JackJohanssonは、実際にはOPがリファラーについて言及しなかった:)彼らは、特定のドメインのAPIエンドポイントをホワイトリストに登録しようとしているように聞こえる「「許可された」URLから来たかどうかを確認したいと言い、OPのコードスニペットでも同じようになります。私にアイデア。
gmazzap
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.