Je souhaite filtrer toute adresse URI de requête HTTP effectuée via l'API HTTP.
Cas d'utilisation:
Les demandes de mise à jour sont les plus importantes pour l’instant, car il ya toujours le bogue non corrigé 16778 ( plus d’informations ), et les requêtes HTTPS réduisent le risque d’une attaque Man-in-the-middle.
J'ai cherchéminutieusement , j'ai étudié le code noyau… mais j'ai fini comme Nacin il y a deux ans:
Je pensais pouvoir filtrer l'URL d'une requête HTTP, mais je ne parviens pas à en trouver une.
Qu'est-ce que j'ai raté? Ai-je? :)
Moins qu'une réponse, mais juste une liste de choses directement de mon expérience avec cela - peut-être avez-vous oublié quelque chose.
Sans entrer trop dans le processus de mise à jour, mais l'API HTTP WP utilise la classe WP_HTTP
. Il offre également une bonne chose: un crochet de débogage.
do_action( 'http_api_debug', $response, 'response', $class, $args, $url );
Où $response
peut également être un objet WP_Error
qui en dit peut-être plus.
Remarque: à partir d'un bref test, ce filtre ne semble fonctionner (pour une raison quelconque) que si vous le placez sous la forme close à l'endroit où vous faites réellement la demande. Alors peut-être devez-vous l'appeler à partir d'un rappel sur l'un des filtres ci-dessous.
WP_HTTP
Arguments de classeLes arguments Classes sont eux-mêmes filtrables, mais certains sont réinitialisés par les méthodes internes à ce que WP suppose nécessaire.
apply_filters( 'http_request_args', $r, $url );
L'un des arguments est ssl_verify
, ce qui est vrai par défaut (mais pour moi, cela pose d'énormes problèmes lors de la mise à jour depuis, par exemple, GitHub). Edit: Après avoir débogué une demande de test, j'ai trouvé un autre argument configuré pour vérifier si SSL est défini sur true
. Cela s'appelle sslverify
(sans séparer le tiret bas). Aucune idée d'où cela entre dans le jeu, s'il est réellement utilisé ou abandonné et si vous avez une chance d'influencer sa valeur. Je l'ai trouvé en utilisant le filtre 'http_api_debug'
.
Vous pouvez également "simplement" remplacer tous les internes et utiliser une configuration personnalisée. Il y a un filtre pour ça.
apply_filters( 'pre_http_request', false, $r, $url );
Le premier argument doit être défini sur true. Ensuite, vous pouvez interagir avec les arguments contenus dans $r
et le résultat de parse_url( $url );
.
Une autre chose qui pourrait fonctionner pourrait être tout exécuter par un proxy personnalisé. Cela nécessite quelques paramètres dans votre wp-config.php
. Je n’avais jamais essayé cela auparavant, mais j’ai passé en revue les constantes il ya quelque temps et ai résumé quelques exemples de ce que devrait travailler et y ai ajouté des commentaires au cas où j’en aurais besoin un jour. Vous devez définir WP_PROXY_Host
et WP_PROXY_PORT
en tant que min. réglage. Sinon, rien ne fonctionnera et cela contournera simplement votre proxy.
# 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' );
La classe WP_HTTP
agit normalement comme base class (sera étendue pour différents scénarios). Les classes WP_HTTP_*
extensibles sont Fsockopen
, Streams
, Curl
, Proxy
, Cookie
, Encoding
. Si vous associez un rappel à l'action 'http_api_debug'
-, le troisième argument vous indiquera quelle classe a été utilisée pour votre demande.
Dans la classe WP_HTTP_curl
, vous trouverez la méthode request()
. Cette méthode propose deux filtres pour intercepter le comportement SSL: un pour les requêtes locales 'https_local_ssl_verify'
et un pour les requêtes distantes 'https_ssl_verify'
. WP va probablement définir local
comme localhost
et ce que vous obtenez en retour de get_option( 'siteurl' );
.
Donc, ce que je ferais est d'essayer le droit suivant avant de faire cette demande (ou d'un rappel qui est lié à la demande la plus proche:
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' );
Note: Dans la plupart des cas, WP_HTTP_curl
sera utilisé pour gérer les procurations.
Sur la base de la réponse utile de @ kaiser, j’ai écrit un code qui semble bien fonctionner. C'est la raison pour laquelle je l'ai marquée comme étant la réponse.
Laissez-moi vous expliquer ma solution…
Lorsqu'une demande envoyée via l'API est exécutée via WP_Http::request()
. C’est la méthode avec…
@todo Refactor ce code.
… Dans son en-tête. Je ne pourrais pas être plus d'accord.
Maintenant, il y a des filtres. J'ai décidé d'abuser pre_http_request
pour mes besoins:
add_filter( 'pre_http_request', 't5_update_wp_per_https', 10, 3 );
Nous avons trois arguments ici: false, $r, $url
.
false
est la valeur de retour attendue pour apply_filters()
. Si nous renvoyons autre chose, WordPress s’arrête immédiatement et la demande initiale ne sera pas envoyée.
$r
est un tableau d'arguments pour cette demande. Nous devons aussi les changer en une minute.
$url
est - surprise! - l'URL.
Donc dans notre callback t5_update_wp_per_https()
nous regardons l'URL, et si c'est une URL que nous voulons filtrer, nous disonsNONà WordPress par non disant "non" (false
) .
Note latérale: Vous pouvez empêcher toutes les requêtes HTTP avec:add_filter( 'pre_http_request', '__return_true' );
Nous lançons notre propre requête à la place avec une meilleure URL et des arguments légèrement ajustés ($r
, renommé en $args
pour plus de lisibilité).
S'il vous plaît lire les commentaires en ligne, ils sont importants.
<?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;
}
Sans ce plugin WordPress utilisé:
http://api.wordpress.org/core/version-check/1.6/
pour les vérifications de mise à jour, ethttp://wordpress.org/wordpress-3.4.2.Zip
pour télécharger les nouveaux fichiers.Je l'ai testé avec deux installations locales, un seul site et une configuration multi-sites sous Win 7. Pour forcer une mise à jour, je règle $wp_version
dans wp-includes/version.php
sur 1
et la version de TwentyEleven sur 1.3
.
Pour regarder le trafic réseau que j’avais utilisé Wireshark : C’est gratuit, il tourne sous Windows et Linux, et il offre des outils de filtrage impressionnants.
Regarder HTTPS est un peu difficile: vous ne voyez que des données chiffrées, c’est l’idée après tout. Pour voir si mon plug-in a fait ce qu'il devrait faire, j'ai d'abord regardé le trafic non chiffré et noté l'adresse IP utilisée pour se connecter à wordpress.org. C'était 72.233.56.138
, parfois 72.233.56.139
.
Sans surprise, il existe un équilibreur de charge et probablement de nombreux autres outils. Nous ne pouvons donc pas compter sur one adresse IP.
Ensuite, j'ai tapé ip.addr == 72.233.56.138
dans le masque de filtrage, activé le plug-in, suis allé à wp-admin/update-core.php
et surveillé le trafic dans Wireshark. Les lignes vertes sont des demandes en texte brut - exactement ce que nous ne voulons pas. Les lignes rouges et noires sont un signe de succès.
La vérification de la mise à jour s'est bien déroulée: les versions "plus récentes" ont été trouvées. Les mises à jour réelles pour le thème et le noyau se sont bien déroulées aussi. Exactement ce dont j'avais besoin.
Et encore… cela pourrait être plus facile s'il y avait un simple filtre pour l'URL.
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);