Фільтрувати будь-який URI запиту HTTP?


10

Я хочу відфільтрувати будь-який URI запиту HTTP, виконаний через HTTP API.

Користувачі:

  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. Деякі плагіни подають запити на інші сервери, і я хочу замінити ці запити, коли зовнішній сервер виходить з ладу.

Наразі запити на оновлення є найважливішими, оскільки все ще існує нефіксований помилка 16778 ( додаткова інформація ), а HTTPS запити знижують ризик атаки "Людина в середині".

Я ретельно шукав , вивчив основний код ... але закінчився як Нацин два роки тому:

Я точно думав, що ви можете відфільтрувати URL-адресу HTTP-запиту, але зараз я не можу його знайти.

Що я пропустив? Чи я? :)


Посилання на цю відповідь тут для тих, хто шукає налагодження CURL у WP.
кайзер

Відповіді:


9

Менше, ніж відповідь, але лише перелік речей, що випливають із мого досвіду роботи, - можливо, ви щось не помітили.

Налагодження запиту та його результати

Без кодування занадто глибоко в процесі оновлення, але WP HTTP API використовує WP_HTTPклас. Також пропонується приємна річ: гак для налагодження.

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

Де $responseтакож може бути WP_Errorоб’єкт, який, можливо, розповість вам більше.

Примітка. Якщо короткий тест, цей фільтр, здається, працює лише (чомусь), якщо розмістити його якнайближче до того, де ви справді робите запит. Тож, можливо, вам потрібно зателефонувати за допомогою зворотного дзвінка на одному з наведених нижче фільтрів.

WP_HTTP Аргументи класу

Самі аргументи класів є фільтруваними, але деякі з них афаіки скидаються внутрішніми методами до того, що WP передбачає, що потрібно.

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

Один з аргументів - ssl_verifyце істинно за замовчуванням (але для мене викликає величезні проблеми при оновленні з - наприклад, GitHub). Редагувати: Після налагодження тестового запиту я знайшов ще один аргумент, встановлений для перевірки, чи встановлено SSL true. Це називається sslverify(не відокремлюючи підкреслення). Не маю уявлення, куди це потрапило в гру, якщо вона насправді використовується або покинута і якщо у вас є шанс вплинути на її значення. Я знайшов це за допомогою 'http_api_debug'фільтра.

Повністю на замовлення

Ви також можете "просто" переосмислити цілі внутрішні сторінки та перейти із власною установкою. Для цього є фільтр.

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

Перший аргумент потрібно встановити на true. Чим ви можете взаємодіяти з аргументами всередині $rта результатом parse_url( $url );.

Проксі

Інша річ, яка може працювати, може запускати все через користувацький проксі. Для цього потрібні деякі налаштування у вашому wp-config.php. Я ніколи раніше цього не пробував, але я пробігся через константи деякий час назад і підсумував кілька прикладів, які повинні працювати, і включив кілька коментарів у випадку, якщо мені це буде потрібно одного дня. Ви повинні визначити WP_PROXY_HOSTі WP_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' );

EDIT

WP_HTTPКлас зазвичай виступає в якості базового класу (буде розширено для різних сценаріїв). Виступаючі WP_HTTP_*класи Fsockopen, Streams, Curl, Proxy, Cookie, Encoding. Якщо ви підключите зворотний виклик до 'http_api_debug'-action, третій аргумент підкаже, який клас використовувався для вашого запиту.

Всередині WP_HTTP_curlкласу ви знайдете request()метод. Цей метод пропонує два фільтри для перехоплення поведінки SSL: один для локальних запитів 'https_local_ssl_verify'і один для віддалених запитів 'https_ssl_verify'. WP, ймовірно, визначатиме localяк localhostі що ви отримуєте взамін від 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буде використовуватися для обробки проксі.


1
Ах, я думаю, ви побічно відповіли на моє запитання: я можу підключитися pre_http_request, скасувати запит і надіслати його з правильною URL-адресою. Спробую це сьогодні ввечері.
фуксія

8

На основі корисної відповіді @ kaiser я написав якийсь код, який, здається, працює добре. Саме тому я позначив це як Відповідь.

Дозвольте мені пояснити своє рішення ...

Логіка

Коли запит, надісланий через API, запускається WP_Http::request(). Це метод з ...

@todo Refactor цей код.

… У своєму заголовку. Я не міг більше погодитися.

Зараз є деякі фільтри. Я вирішив неправильно використовувати pre_http_requestдля своїх потреб:

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

Ми отримуємо три аргументи тут: false, $r, $url.

  • false- очікуване значення повернення для apply_filters(). Якщо ми повернемо щось інше назад, WordPress негайно зупиняється, і оригінальний запит не буде надісланий.

  • $r- це масив аргументів для цього запиту. Ми також повинні їх змінити за хвилину.

  • $urlє - сюрприз! - URL-адреса.

Отже, у зворотному дзвінку t5_update_wp_per_https()ми дивимось на URL-адресу, і якщо це URL-адреса, яку ми хочемо відфільтрувати, ми говоримо « НЕ» WordPress, не кажучи «ні» ( false).

введіть тут опис зображення

Бічна примітка. Звідси випливає, що ви можете запобігти усім 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. Для того, щоб змусити набір оновлень I $wp_versionв wp-includes/version.phpдо 1і версії TwentyEleven до 1.3.

Для перегляду мережевого трафіку я використав Wireshark : Він безкоштовний, він працює в Windows та Linux, і він пропонує деякі вражаючі засоби фільтрування.

Перегляд HTTPS трохи складний: ви бачите лише зашифровані дані ... ось така ідея. Щоб побачити, чи зробив мій плагін те, що треба, я спочатку переглянув незашифрований трафік і зазначив IP-адресу, яка використовується для підключення до wordpress.org. Так було 72.233.56.138, іноді 72.233.56.139.
Не дивно, що є балансир навантаження і, мабуть, багато інших інструментів, тому ми не можемо покластися на одну IP-адресу.

Потім я набрав ip.addr == 72.233.56.138у маску фільтра, активував плагін, зайшов wp-admin/update-core.phpі стежив за трафіком у Wireshark. Зелені лінії - це запити в простому тексті - саме те, чого ми не хочемо. Червоні та чорні лінії - знак успіху.

Wireshark

Перевірка оновлення пройшла нормально: вона знайшла "новіші" версії. Фактичні оновлення теми та основної програми також вийшли чудовими. Саме те, що мені було потрібно.

І все ж… це може бути простіше, якби був простий фільтр для URL-адреси.


1
+1 для /* /**/, просто тому, що це геніально. І (якщо зможу) ще +1 для Чарльза Бронсона. І тоді має бути ще один +1 для детального пояснення, коментарів та скріншотів.
кайзер

3
    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
Слід зазначити, що в цьому прикладі коду у функції http_api_curl_custom глобальна змінна $ substitu_url повинна бути встановлена ​​на NULL після її використання. Інакше після першого виникнення "wordpress.org" в URL-адресі всі інші URL-адреси будуть замінені.
MihanEntalpo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.