web-dev-qa-db-ja.com

HTTPリクエストURIをフィルタリングしますか?

HTTP APIを通じて行われたHTTPリクエストURIをフィルタリングしたい。

ユースケース

  1. WordPressのアップデートチェックは http://api.wordpress.org/core/version-check/1.6/ に行きますが、 https://api.wordpress.org/core/version-check/1.6/ でも動作します、そして私はこれをいつも使いたいのです。
  2. 新しいWordPressファイルは http://wordpress.org/wordpress-3.4.2.Zip から取得されますが、 https://wordpress.org/wordpress-3.4.2.Zip も動作します。
  3. 時々私は要求をデバッグし、それらを私のローカルサーバー上のカスタムドメインに一時的にリダイレクトしたいです。
  4. いくつかのプラグインは他のサーバーにリクエストを出します、そして私は外部サーバーがダウンしたときにこれらのリクエストを置き換えたいと思います。

まだ修正されていない bug 16778more information )があり、HTTPSリクエストは中間者攻撃のリスクを低くするので、更新リクエストは今のところ最も重要なものです。

検索徹底的に 、私はコアコードを勉強しました…しかし2年前にNacinのように終わった:

私はあなたがHTTPリクエストのURLを確実にフィルタリングすることができると考えました、しかし今私はそれを見つけることができません。

私は何を取りこぼしたか?私はしましたか? :)

9
fuxia

答えにはなりませんが、私の経験から直接引用したもののリストです。何かを見落としているかもしれません。

リクエストとその結果をデバッグする

Digginがないと更新処理が深くなりすぎますが、WP HTTP APIはWP_HTTPクラスを使用します。デバッグフックという素晴らしいこともあります。

do_action( 'http_api_debug', $response, 'response', $class, $args, $url );

$responseWP_Errorオブジェクトになることもできます。

注:簡単なテストでは、このフィルターは(何らかの理由で)実際にリクエストを行っている場所に close のように配置した場合にのみ機能するようです。そのため、以下のいずれかのフィルタでコールバック内から呼び出す必要があります。

WP_HTTPクラス引数

Classesの引数自体はフィルタリング可能ですが、内部のメソッドによってWPが必要と見なしているものにリセットされることがよくあります。

apply_filters( 'http_request_args', $r, $url );

引数の1つはssl_verifyで、これはデフォルトでtrueです(しかし、私にとっては、たとえばGitHubからアップデートすると大きな問題が発生します)。 編集: テストリクエストをデバッグした後、SSLがtrueに設定されているかどうかを検証するために設定されている別の引数を見つけました。これはsslverifyと呼ばれます(アンダースコアを区切らずに)。それが実際に使われているか放棄されているかどうか、そしてあなたがその価値に影響を与えるチャンスがあるかどうか、これがゲームのどこに入ったのか見当がつかない。 'http_api_debug'フィルタを使って見つけました。

完全にカスタム

内部構造全体を「単純に」オーバーライドしてカスタム設定を使用することもできます。そのためのフィルタがあります。

apply_filters( 'pre_http_request', false, $r, $url );

最初の引数はtrueに設定する必要があります。あなたは$r内の引数とparse_url( $url );からの結果と対話することができます。

プロキシ

もう1つうまくいく可能性があるのは、カスタムProxyを通してすべてを実行することです。これはあなたのwp-config.phpでいくつかの設定を必要とします。これまで試したことは一度もありませんでしたが、しばらく前に定数を調べて、 should workという例をいくつかまとめて、必要に応じてコメントを含めました。 WP_PROXY_HostWP_PROXY_PORTを最小値として定義する必要があります。設定さもなければ何も働かないでしょう、そしてそれは単にあなたのプロキシを迂回するでしょう。

# HTTP Proxies
# Used for e.g. in Intranets
# Fixes Feeds as well
# Defines the proxy adresse.
define( 'WP_PROXY_Host',          '127.0.84.1' );
# Defines the proxy port.
define( 'WP_PROXY_PORT',          '8080' );
# Defines the proxy username.
define( 'WP_PROXY_USERNAME',      'my_user_name' );
# Defines the proxy password.
define( 'WP_PROXY_PASSWORD',      'my_password' );
# Allows you to define some adresses which
# shouldn't be passed through a proxy.
define( 'WP_PROXY_BYPASS_HOSTS',  'localhost, www.example.com' );

編集

WP_HTTPクラスは通常 base classとして機能します(さまざまなシナリオに対応するように拡張されます)。拡張するWP_HTTP_*クラスはFsockopenStreamsCurlProxyCookieEncodingです。コールバックを'http_api_debug'-アクションにフックすると、3番目の引数はどのクラスがあなたのリクエストに使われたかを教えてくれます。

WP_HTTP_curlクラスの中には、request()メソッドがあります。このメソッドは、SSLの振る舞いを傍受するための2つのフィルタを提供します。1つはローカル要求'https_local_ssl_verify'、もう1つはリモート要求'https_ssl_verify'です。 WPはおそらくlocallocalhostとして定義し、あなたがget_option( 'siteurl' );から得たものを定義するでしょう。

そのため、そのリクエストを実行する直前に(または最も近いリクエストにフックされたコールバックから)、次のことを試してください。

add_filter( 'https_ssl_verify', '__return_true' );

# Local requests should be checked with something like
# 'localhost' === $_SERVER['HTTP_Host'] or similar
# add_filter( 'https_local_ssl_verify', '__return_true' );

サイドノート:ほとんどの場合、WP_HTTP_curlがプロキシの処理に使用されます。

8
kaiser

@kaiserの有用な回答に基づいて、うまく機能していると思われるコードをいくつか書きました。それが私が答えとしてマークした理由です。

私の解決策を説明させてください…

ロジック

APIを介して送信されたリクエストがWP_Http::request()を介して実行される場合。それが…の方法です

@todoこのコードをリファクタリングします。

…ヘッダーに。私はこれ以上同意できませんでした。

現在、いくつかのフィルターがあります。私は私のニーズのためにpre_http_requestを誤用することにしました:

add_filter( 'pre_http_request', 't5_update_wp_per_https', 10, 3 );

ここで3つの引数を取得します:false, $r, $url

  • falseは、apply_filters()の期待される戻り値です。他に何かを送り返すと、WordPressはすぐに停止し、元のリクエストは送信されません。

  • $rは、そのリクエストの引数の配列です。これらも1分で変更する必要があります。

  • $urlは–驚きです! – URL。

そのため、コールバックt5_update_wp_per_https()でURLを確認し、それがフィルタリングしたいURLである場合、NOto WordPress bynot“ no”(false)と言います。

enter image description here

補足:すべてのHTTPリクエストを次の方法で防ぐことができます:
add_filter( 'pre_http_request', '__return_true' );

代わりに、より良いURLとわずかに調整された引数($r、読みやすくするために$argsに名前を変更)を使用して独自のリクエストを実行します。

コード

インラインコメントを読んでください、それらは重要です。

<?php
/**
 * Plugin Name: T5 Update WP per HTTPS
 * Description: Forces update checks and downloads for WP to use HTTPS.
 * Plugin URI:  http://wordpress.stackexchange.com/questions/72529/filter-any-http-request-uri
 * Version:     2012.11.14
 * Author:      Thomas Scholz
 * Author URI:  http://toscho.de
 * Licence:     MIT
 * License URI: http://opensource.org/licenses/MIT
 */

add_filter( 'pre_http_request', 't5_update_wp_per_https', 10, 3 );

/**
 * Force HTTPS requests for update checks and new WP version downloads.
 *
 * @wp-hook pre_http_request
 * @param   bool   $false
 * @param   array  $args
 * @param   string $url
 * @return  FALSE|array|object FALSE if everything is okay, an array of request
 *                            results or an WP_Error instance.
 */
function t5_update_wp_per_https( $false, $args, $url )
{
    // Split the URL into useful parts.
    $url_data = parse_url( $url );

    // It is already HTTPS.
    if ( 'https' === strtolower( $url_data['scheme'] ) )
        return FALSE;

    // Not our Host.
    if ( FALSE === stripos( $url_data['Host'], 'wordpress.org' ) )
        return FALSE;

    // Make that an HTTPS request.
    $new_url = substr_replace( $url, 'https', 0, 4 );

    // WP_Http cannot verify the wordpress.org certificate.
    $args['sslverify'] = FALSE;

    // It is slow. We wait at least 30 seconds.
    30 > $args['timeout'] and $args['timeout'] = 30;

    // Get an instance of WP_Http.
    $http    = _wp_http_get_object();

    // Get the result.
    $result = $http->request( $new_url, $args );

    /* prepend this line with a '#' to debug like a boss.
    print '<pre>'
    . htmlspecialchars( print_r( $result, TRUE ), ENT_QUOTES, 'utf-8', FALSE )
    . '</pre>';
    die();
    /**/

    return $result;
}

テスト

そのプラグインなしでWordPress使用:

  • http://api.wordpress.org/core/version-check/1.6/更新チェック用、および
  • http://wordpress.org/wordpress-3.4.2.Zipをクリックして、新しいファイルをダウンロードします。

Win 7で2つのローカルインストール、単一サイトおよびマルチサイトセットアップでテストしました。更新を強制するには、$wp_versionwp-includes/version.php1に設定し、TwentyElevenのバージョンを1.3

私が使用したネットワークトラフィックを監視するために Wireshark :無料で、WindowsとLinuxで実行され、いくつかの印象的なフィルターツールを提供します。

HTTPSを見るのは少し難しいです。暗号化されたデータだけが表示されます。プラグインが何をすべきかを確認するために、まず暗号化されていないトラフィックを監視し、wordpress.orgへの接続に使用されたIPアドレスを書き留めました。それは72.233.56.138、時には72.233.56.139でした。
驚くべきことではありませんが、ロードバランサーとおそらく他の多くのツールがあるため、oneIPアドレスに依存することはできません。

次に、フィルターマスクにip.addr == 72.233.56.138と入力し、プラグインをアクティブにし、wp-admin/update-core.phpに移動して、Wiresharkのトラフィックを監視しました。緑の線はプレーンテキストでのリクエストであり、まさに私たちが望まないものです。赤と黒の線は成功の兆候です。

Wireshark

更新チェックはうまくいきました。「新しい」バージョンが見つかりました。テーマとコアの実際の更新もうまくいきました。まさに私が必要なもの。

それでも…URLに簡単なフィルターがあればもっと簡単になります。

8
fuxia
    add_filter('http_request_args', 'http_request_args_custom', 10,2);
    function http_request_args_custom($request,$url){
            if (strpos($url, 'wordpress.org') !== false){
                    global $replaced_url;
                    $replaced_url = 'http://wordpress.local';
            }
            return $request;
    }

    add_action('http_api_curl', 'http_api_curl_custom');
    function http_api_curl_custom(&$handle){
            global $replaced_url;
            if (!is_null($replaced_url))
                    curl_setopt( $handle, CURLOPT_URL, $replaced_url);
    }

    $http = new WP_Http();
    $response = $http->request('http://wordpress.org', array());

    var_dump($response);
1
Butuzov