A la une wp-login.pdf

Modifier l’accès à wp-login.php

Le fichier « wp-login.php » gère la connexion, mais aussi la réinitialisation des mots de passe, la déconnexion, la reconnexion pour renouveler une session expirée ainsi que la possibilité pour un visiteur de s’inscrire en ligne.
Modifier l’accès au fichier wp-login.php protège la partie administration du site qui permet de gérer le site : publier des articles, créer des utilisateurs, ajouter des extensions…

Ce tutoriel présente une extension (plugin) qui modifie l’adresse de connexion standard (wp-login.php) et bloque l’utilisation des adresses « alias » : login, wp-admin, admin et dashboard. Elle fonctionne en mono-site et en multi-site.
Il suffit de la placer dans le répertoire « plugins », ou encore mieux le répertoire « mu-plugins ».

Les pirates scrutent le web à la recherche de sites WordPress auxquelles ils tentent de se connecter à partir de l’adresse standard de connexion (wp-login.php) ou via les adresses « alias » : login, wp-admin, admin et dashboard.
Ils testent divers identifiants / mots de passe connus pour être utilisés (« admin », « 123456 »…), ou essaient énormément de combinaisons dans le cas d’une attaque de type force brute.
Changer l’adresse de connexion, c’est rendre inopérantes ces tentatives.
Attention : cela ne change rien à une attaque visant un site particulier, si l’adresse de connexion est visible par n’importe quel visiteur du site.

Haut de page

Initialisation

La première étape de l’extension consiste à créer deux constantes php contenant la valeur de la nouvelle adresse de connexion (ici : « coucou ») et de l’adresse de la page de refus qui sera affichée si le visiteur tente de se connecter par l’adresse standard ou un alias (ici, la page d’accueil) :

//    définir la nouvelle adresse de connexion
define('WPDF_ADRESSE_CONNEXION', 'coucou');

//    définir l'adresse de retour quand la connexion est refusée (exemple : la page d'accueil)
define('WPDF_ADRESSE_CONNEXION_REFUSEE', network_site_url());

Ces constantes sont utilisées par les autres fonctions de l’extension.

Choisissez  l’adresse de connexion en évitant ce qui pourrait être l’adresse d’un article ou d’une page. N’hésitez pas à en faire un véritable mot de passe, avec des lettres minuscules et majuscules, des chiffes et des caractères non alphabétiques, mais sans utiliser des caractères qui ont un sens dans une url (« ? », « # »). Par exemple, plutôt que « coucou », utilisez « Cou_c2o4@U6! » beaucoup plus difficile à trouver.

La fonction network_site_url() renvoie l’adresse de la page d’accueil pour les sites en « muti-site » (une seule installation de WordPress gère plusieurs sites). Si l’installation est en mono-site, network_site_url() appelle la fonction site_url().

Haut de page

Rediriger la nouvelle adresse vers le formulaire de connexion

La deuxième étape consiste à insérer une fonction qui déclenche l’exécution du fichier « wp-login.php » lorsque l’url saisie par le visiteur du site correspond à l’adresse de connexion modifiée.

add_action( 'init', 'wpdf_redirige_login' );

function wpdf_redirige_login()  {
    
    $wpdf_adresse_connexion = '/'.WPDF_ADRESSE_CONNEXION;    //    adresse de base

    $wpdf_patron='#' . $wpdf_adresse_connexion.'$|' . $wpdf_adresse_connexion . '/?\?action=rp&?|' . $wpdf_adresse_connexion.'/?\?loggedout=true$|' . $wpdf_adresse_connexion . '/?\?checkemail=confirm$|' . $wpdf_adresse_connexion.'/?\?checkemail=registered$|' . $wpdf_adresse_connexion . '/?\?action=lostpassword&?$|' . $wpdf_adresse_connexion . '/?\?action=lostpassword&error=expiredkey$|' . $wpdf_adresse_connexion . '/?\?action=lostpassword&error=invalidkey$|' . $wpdf_adresse_connexion . '/?\?action=resetpass$|' . $wpdf_adresse_connexion.'/?\?registration=disabled$|' . $wpdf_adresse_connexion . '/?\?action=register|' . $wpdf_adresse_connexion . '/?\?checkemail=registered$|' . $wpdf_adresse_connexion . '/?\?interim-login=1$|' . $wpdf_adresse_connexion . '/?\?redirect_to=|' . $wpdf_adresse_connexion . '\?action=lostpassword&error=expiredkey|' . $wpdf_adresse_connexion . '\?action=lostpassword&error=invalidkey|' . $wpdf_adresse_connexion . '\?registration=disabled|' . $wpdf_adresse_connexion . '/?\?action=logout&_wpnonce=#';
        
    if (preg_match($wpdf_patron, untrailingslashit( $_SERVER['REQUEST_URI'])) === 1 ) {
        error_reporting(E_ALL & ~E_NOTICE);
        require_once(ABSPATH . 'wp-login.php');
        exit();
    }    //    fin test si nouvelle url de connexion
}    //    fin fonction wpdf_redirige_login

La fonction « wpdf_redirige_login() » est ajoutée au crochet de type action « init »  qui se déclenche après le chargement de WordPress et avant l’affichage de la page demandée :

add_action( ‘init‘, ‘wpdf_redirige_login‘ );

Adresse à rechercher

Nous commençons par définir une variable contenant la portion d’adresse que nous souhaitons reconnaître dans l’url :

$wpdf_adresse_connexion = « / ».WPDF_ADRESSE_CONNEXION;    //    adresse de base

Nous pourrions nous contenter de rechercher la chaîne de caractères correspondant à l’adresse de connexion (« WPDF_ADRESSE_CONNEXION »). Mais il suffirait que l’adresse se trouve n’importe où dans l’url (par exemples : « monsite.fr/abracoucou » ou « monsite.fr/autre_chose/?coucou=“FAUX” »…) pour déclencher l’exécution du fichier « wp-login.php ».
En recherchant l’adresse « /coucou » plutôt que « coucou », on élimine ces cas parasites, mais cela n’élimine pas une adresse comme « monsite.fr/coucouxxx ».

Utilisation des expressions régulières

« wp-login.php » est un programme qui crée des liens vers lui même avec un paramétrage correspondant à l’action à réaliser : se connecter, changer le mot de passe, créer un utilisateur…  Pour repérer ce paramétrage qui correspond aux adresses devant déclencher l’exécution de « wp-login.php », il suffit d’éditer le fichier « wp-login.php » et de rechercher la chaîne de caractères « wp-login.php » :

modifier wp-login.php
liens vers wp-login.php dans wp-login.php

Nous utilisons les expressions régulières pour s’assurer que nous ne lançons l’exécution de « wp-login.php » que pour les types d’url souhaités.

Le « patron » permet de définir les différentes structures d’url qui seront acceptées pour accéder au fichier « wp-login.php ».  Voici la valeur de $wpdf_patron si l’adresse de connexion est « coucou » :

'#/coucou$|/coucou/?\?action=rp&?|/coucou/?\?loggedout=true$|/coucou/?\?checkemail=confirm$|/coucou/?\?checkemail=registered$|/coucou/?\?action=lostpassword&?$|/coucou/?\?action=lostpassword&error=expiredkey$|/coucou/?\?action=lostpassword&error=invalidkey$|/coucou/?\?action=resetpass$|/coucou/?\?registration=disabled$|/coucou/?\?action=register|/coucou/?\?checkemail=registered$|/coucou/?\?interim-login=1$|/coucou/?\?redirect_to=|/coucou\?action=lostpassword&error=expiredkey|/coucou\?action=lostpassword&error'...

On constate qu’on identifie un certain nombre de paramètres pour l’url de sous-domaine « coucou » : « action=rp », « loggedout=true »…

Expliquer toute la richesse des expressions régulières dépasse largement le sujet de ce tutoriel, mais pour en faire comprendre les principes de fonctionnement, voici l’analyse du début du « patron » :

$wpdf_patron=’#‘ . $wpdf_adresse_connexion.’$|‘ . $wpdf_adresse_connexion . ‘/?\?action=rp&?
. . . . .
|’ . $wpdf_adresse_connexion . ‘/?\?action=logout&_wpnonce=#‘;

  • « # » : indique le début du patron; le patron doit se terminer par le même caractère : « action=logout&_wpnonce=#»,
  • « $wpdf_adresse_connexion » : l’adresse de connexion préfixée par le caractère « / » comme défini précédemment,
  • « $ » : indique la fin de portion de chaîne qu’on cherche à reconnaître; dans l’exemple, « $wpdf_adresse_connexion.’$ » définit une portion de chaîne se terminant par l’adresse de connexion (exemple : « monsite.fr/coucou », mais pas « monsite.fr/coucou?param=“VRAI” »),
  • « | » : représente le « ou », c’est à dire qu’une autre portion de chaîne va permettre de définir une autre adresse acceptable,
  • « ? » : le caractère « ? » permet de préciser que ce qui est juste avant est optionnel; dans notre exemple, « /coucou/ » et « /coucou » sont deux valeurs possibles,
  • « \ » : le caractère « \ » permet de préciser que le caractère suivant doit être considéré comme un caractère « standard » et non pas un caractère réservé des expressions régulières;
    les chaînes « /coucou/?action=rp&truc=“abracadabra” ou « /coucou?action=rp&truc=“abracadabra” sont valables.

L’intérêt d’utiliser les expressions régulières est double :

  • bloquer les tentatives malveillantes en n’exécutant le fichier « wp-login.php » que si l’url  correspond à une structure acceptée,
  • ne pas déclencher l’exécution involontaire du fichier « wp-login.php » si une url « ressemble » à un appel de « wp-login.php »; avec les dizaines de milliers d’extensions disponibles, les homonymies involontaires sont un vrai risque.

Les expressions régulières offrent bien d’autres possibilités et de nombreux tutoriels peuvent être trouvés sur internet.

Exécuter le fichier « wp-login.php »

Si l’url contient la nouvelle adresse de connexion de façon conforme au « patron », on lance l’exécution du fichier  « wp-login.php » pour afficher le formulaire de connexion (ou les formulaires de réinitialisation de mots de passe ou de reconnexion après une fin de session) :

if (preg_match($wpdf_patron, untrailingslashit( $_SERVER[‘REQUEST_URI’])) === 1 ) {
error_reporting(E_ALL & ~E_NOTICE);
require_once(ABSPATH . ‘wp-login.php’);
exit();
}

« $_SERVER[‘REQUEST_URI’] » est l’adresse (url) saisie dans son navigateur internet par le visiteur (ou utilisée par le programme de recherche de sites d’un pirate).

« preg_match() » est la fonction qui vérifie la compatibilité de l’url par rapport au patron. Si le résultat est égal à 1, c’est que l’url correspond à au moins une structure définie dans le patron.

« untrailingslashit() » est une fonction de WordPress qui permet de retirer une éventuelle barre oblique en fin de chaîne de caractères (ici, en fin d’url).

L’exécution de « wp-login.php » déclenche un message d’erreur du fait d’une redéclaration de constante : PHP Notice:  Constant ABSPATH already defined. Le code suivant gère cette (petite) difficulté :

error_reporting(E_ALL & ~E_NOTICE);

La fonction php « error_reporting()« , permet de signaler toutes les erreurs, sauf les erreurs de type « Notice ». Cela évite de perturber l’affichage ou d’écrire des messages inutiles dans le journal des erreurs.

L’instruction suivante permet de lancer l’exécution du fichier « wp-login.php » situé à la racine de WordPress :

require_once(ABSPATH . ‘wp-login.php’);

La constante « ABSPATH » est valorisée, dans le fichier « wp-config.php », à l’adresse de la racine de l’installation WordPress accédée par le serveur (et non l’url permettant d’y accéder par internet).

/** Chemin absolu vers le dossier de WordPress. */
if ( !defined('ABSPATH') )
    define('ABSPATH', dirname(__FILE__) . '/');

« require_once() » est une fonction php qui déclenche l’exécution du fichier de programme passé en paramètre (ici, le fichier « wp-login.php » situé à la racine de l’installation WordPress).

La fonction php « exit() » stoppe l’exécution du script php en cours. Nous l’insérons ici pour éviter que php n’exécute la suite des instructions de l’extension après avoir exécuté « wp-login.php ».

Désormais, saisir l’adresse « nom_du_site/coucou » permet d’afficher le formulaire de connexion :

Modifier wp-login.php - formulaire de connexion via nouvelle adresse
Se connecter via nouvelle adresse

À noter :

    • une solution alternative très répandue, consiste à introduire la consigne « RewriteRule » dans le fichier .htaccess situé à la racine du site, avant les consignes WordPress (voir article sur la redirection avec htaccess) :
      RewriteRule ^NomConnexion$ wp-login.php
      # BEGIN WordPress
      <IfModule mod_rewrite.c>
      ...

      Cela fonctionne, mais il faut veiller à ce que « NomConnexion » utilisé dans .htaccess corresponde toujours à la nouvelle adresse définie dans l’extension. Si on veut modifier la nouvelle adresse de connexion, il faut le faire simultanément à deux endroits : dans l’extension et dans le fichier .htaccess.

    • il existe d’autres extensions permettant de changer l’adresse de connexion d’un site; saisissez par exemple « WordPress plugin move login » dans un moteur de recherche pour en trouver plusieurs.
Haut de page

Modifier l’adresse de connexion

Utiliser les crochets « network_site_url » et « site_url »

Les liens de connexion qui s’affichent sur le site continuent à pointer vers « wp-login.php » :

Modifier wp-login.php - Les liens pointent vers wp-login.php
Les liens pointent vers wp-login.php

Nous devons les faire pointer vers la nouvelle adresse de connexion.

Les deux crochets « network_site_url » et « site_url » sont utilisés pour créer des url, l’un pour des installations multi-sites, l’autre pour les installations mono-site. Voici le code que nous utilisons :

add_filter( 'site_url', 'wpdf_modifie_adresse_connexion', 10, 3 );
if (is_multisite()) add_filter( 'network_site_url', 'wpdf_modifie_adresse_connexion', 10, 3 );

function wpdf_modifie_adresse_connexion( $wpdf_aff_login_url, $wpdf_path, $wpdf_orig_scheme ) {

    if ( $wpdf_orig_scheme === 'login' || $wpdf_orig_scheme === 'login_post' ){
        $wpdf_aff_login_url = preg_replace( '/wp-login\.php/', WPDF_ADRESSE_CONNEXION, $wpdf_aff_login_url, 1 );
    }    //    fin test si scheme égal login ou login_post

    $wpdf_siteurl_patron = '#wp-login.php\?action=lostpassword&error=expiredkey$|wp-login.php\?action=lostpassword&error=invalidkey$|wp-login.php\?registration=disabled$#';

    if ( preg_match($wpdf_siteurl_patron, $wpdf_aff_login_url) === 1  )
        $wpdf_aff_login_url = preg_replace( '/wp-login\.php/', WPDF_ADRESSE_CONNEXION, $wpdf_aff_login_url, 1 );    
    return $wpdf_aff_login_url;
}    // fin fonction wpdf_modifie_adresse_connexion

Ajouter la fonction « wpdf_modifie_adresse_connexion » au crochet site_url, et au crochet network_site_url si l’installation est multi-site :

add_filter( ‘site_url‘, ‘wpdf_modifie_adresse_connexion‘, 10, 3 );
if (is_multisite()) add_filter( ‘network_site_url‘, ‘wpdf_modifie_adresse_connexion‘, 10, 3 );

  • « 10 » est la priorité qui permet de définir l’ordre d’exécution des fonctions ajoutées à un filtre;
    « 10 » est la priorité par défaut, les priorités inférieures sont exécutées plus tôt, les priorités supérieures sont exécutées plus tard,
  • « 3 » est le nombre de paramètres qui seront passés aux fonctions ajoutées au filtre

La fonction vérifie si le troisième paramètre passé est égal à « login » ou « login_post».
En effet, les crochets « {network_}site_url », insérés dans les fonctions « {network_}site_url() » peuvent être appelés pour traiter n’importe qu’elle url. En revanche, les schémas (scheme) « login » et « login_post » ne sont utilisés que pour des url de connexion :

Appel de la fonction network_site_url() avec le scheme login dans wp-login.php
Appel de la fonction network_site_url() avec le scheme login dans wp-login.php

Voici le test ajouté dans la fonction appelée dans le crochet {network_}site_url :

if ( $wpdf_orig_scheme === ‘login‘ || $wpdf_orig_scheme === ‘login_post‘ ){

Si la condition est vérifiée, la fonction remplace dans l’url passée en paramètre « wp-login.php » par la nouvelle adresse de connexion :

$wpdf_aff_login_url = preg_replace( ‘/wp-login.php/‘, WPDF_ADRESSE_CONNEXION, $wpdf_aff_login_url, 1 );

La fonction php « preg_replace » permet d’effectuer un remplacement de chaînes de caractères en utilisant une expression régulière (on peut remarquer que le début de l’expression régulière est un « / » et non plus un « # » comme précédemment; l’important est que le caractère choisi soit identique pour commencer et terminer l’expression régulière).

L’url, éventuellement modifiée, est renvoyée au programme appelant « {network_}site_url() » :

return $wpdf_aff_login_url;

On peut vérifier que l’adresse des liens de connexion sont modifiés, « coucou » ayant remplacé « wp-login.php »  :

Modifier wp-login.php - Nouvelle adresse pour récupérer le mot de passe
Nouvelle adresse pour récupérer le mot de passe
Modifier wp-login.php - Nouvelle adresse de connexion
Nouvelle adresse de connexion
déplacer wp-login.php - lien d'inscription d'un nouvel utilisateur
Modifier le lien d’inscription d’un nouvel utilisateur
Modifier wp-login.php - Nouvelle adresse de déconnexion
Nouvelle adresse de déconnexion

D’autres liens, utilisés dans les courriels envoyés à l’utilisateur pour lui permettre de valider un nouveau mot de passe, sont créés via « {network_}site_url » mais pas avec les scheme « login » ou « login_post » :

Modifier les liens vers "wp-login.php" - Appel de site_url() sans un schéma de login
Appel de site_url() sans un schéma de login

Nous utilisons les expressions régulières pour les identifier :

$wpdf_siteurl_patron = ‘#wp-login.php\?action=lostpassword&error=expiredkey$|wp-login.php\?action=lostpassword&error=invalidkey$|wp-login.php\?registration=disabled$#’;

Si l’url passée en paramètre de « {network_}site_url() » correspond à une structure définie dans le patron de l’expression régulière, on remplace « wp-login.php » par la nouvelle adresse de connexion, et on renvoie l’url modifiée :

if ( preg_match($wpdf_siteurl_patron, $wpdf_aff_login_url) === 1  )
$wpdf_aff_login_url = preg_replace( ‘/wp-login\.php/‘, WPDF_ADRESSE_CONNEXION, $wpdf_aff_login_url, 1 );
return $wpdf_aff_login_url;

Utiliser le crochet « wp_redirect »

Dans le processus de modification du mot de passe, « wp-login.php » crée des liens sans passer pas par les crochets {network_}site_url.
Nous allons utiliser le crochet « wp_redirect » pour remplacer le lien vers « wp-login.php » par un lien vers la nouvelle adresse de connexion.

wp-redirect pour modifier le lien vers wp-login.php dans wp-login.php
Appel de wp-login dans wp-login – utilisation du filtre wp_redirect
Demande de génération d'un nouveau mot de passe pour un utilisateur
Demande de génération d’un nouveau mot de passe pour un utilisateur

L’écran suivant doit apparaître si le courriel a été envoyé (si on ne change rien, l’appel au fichier « wp-login.php » va être filtré, et on est redirigé vers la page de refus de connexion) :

Ecran de confirmation de l'envoi du courriel pour modifier le mot de passe
Confirmation de l’envoi du courriel pour modifier le mot de passe

Le code ci-dessous permet de modifier le lien vers l’affichage de la réussite d’envoi d’un nouveau mot de passe :

add_filter ('wp_redirect', 'wpdf_redirect_mdpout', 10, 2);

function wpdf_redirect_mdpout ( $wpdf_location, $wpdf_status ) {
    $wpdf_redirect_mdpout = array (
        'wp-login.php?loggedout=true',
        'wp-login.php?checkemail=confirm',
        'wp-login.php?checkemail=registered'
    );
    if ( in_array( $wpdf_location, $wpdf_redirect_mdpout ) )
        $wpdf_location = preg_replace( '/wp-login\.php/', WPDF_ADRESSE_CONNEXION, $wpdf_location, 1 );
    return $wpdf_location;
}    // fin fonction wpdf_redirect_mdpout

Ajouter la fonction « wpdf_redirect_mdpout »au crochet « wp_redirect » :

add_filter (‘wp_redirect’, ‘wpdf_redirect_mdpout’, 10, 2)

Si l’adresse passée pour la redirection est « wp-login.php?checkemail=confirm« , on la modifie en remplaçant « wp-login.php » par la nouvelle adresse de connexion :

if(‘wp-login.php?checkemail=confirm‘ == $wpdf_location)
$wpdf_location = WPDF_ADRESSE_CONNEXION.’?checkemail=confirm’

On retourne ensuite l’adresse éventuellement modifiée qui sera utilisée pour effectuer la redirection :

return $wpdf_location;

Haut de page

Utiliser le crochet « update_welcome_email »

Le message de bienvenue envoyé par courriel pour la création d’un nouveau site contient un lien de connexion qui dirige vers « wp-login.php » :

Référence à "wp-login.php" dans le courriel de bienvenue
Lien de connexion vers un nouveau site dans le courriel de bienvenue

Ce lien vers « wp-login.php » n’est filtré ni par « {network_}site_url » ni par « wp_redirect ». Heureusement, nous pouvons utiliser le crochet de type filtre « update_welcome_email » :

Appel du filtre "update_welcome_email" dans le programme wp-includes/ms-functions.php
Appel du filtre « update_welcome_email » dans le programme wp-includes/ms-functions.php

Voici le code pour remplacer la référence à « wp-login.php » par une référence à la nouvelle adresse de connexion :

add_filter ('update_welcome_email', 'wpdf_update_welcome_email', 10, 6);

function wpdf_update_welcome_email ( $wpdf_welcome_email, $wpdf_blog_id, $wpdf_user_id, $wpdf_password, $wpdf_title, $wpdf_meta) {
 $wpdf_welcome_email = preg_replace( '/wp-login\.php/', WPDF_ADRESSE_CONNEXION, $wpdf_welcome_email, 1 );
 return $wpdf_welcome_email;
 }    // fin fonction wpdf_update_welcome_email

Le filtre « update_welcome_email » n’étant appelé qu’avant l’envoi du courriel de bienvenue, il n’est pas nécessaire de faire un test pour s’assurer qu’on ne modifiera que ce courriel. C’est une différence importante avec un filtre tel que « site_url » qui est appelé pour créer toutes sortes d’url.

Nous avons utilisé la fonction « preg_replace » mais nous aurions pu tout aussi bien utiliser la fonction « str_replace, » car on cherche à remplacer une chaîne de caractères par une autre sans se soucier de sa conformité à une structure particulière.

Haut de page

Filtrer les demandes de connexion

Il nous faut maintenant vérifier que la connexion ne puisse se faire qu’à partir de la nouvelle adresse :

add_action( 'login_init', 'wpdf_refuse_connexion' );

function wpdf_refuse_connexion() {
    if ( strpos( $_SERVER['REQUEST_URI'], '/'.WPDF_ADRESSE_CONNEXION ) === false ) {
        wp_redirect( WPDF_ADRESSE_CONNEXION_REFUSEE );
        exit();
    }    // fin test si nouvelle adresse de connexion non trouvée
}    //    fin fonction wpdf_refuse_connexion

Ajouter la fonction « wpdf_refuse_connexion() » au crochet de type action « login_init »  qui se déclenche avant l’affichage du formulaire de connexion :

add_action( ‘login_init‘, ‘wpdf_refuse_connexion‘ );

La fonction renvoie vers la page de refus de connexion si la connexion n’est pas demandée via la nouvelle adresse :

if ( strpos( $_SERVER[‘REQUEST_URI’], ‘/’.WPDF_ADRESSE_CONNEXION ) === false ) {
wp_redirect( WPDF_ADRESSE_CONNEXION_REFUSEE );
exit();
}    // fin test si nouvelle adresse de connexion non trouvée

Ayant lancé l’affichage d’une autre page, nous stoppons l’exécution de WordPress qui était en cours en appelant la fonction php « exit() ».

Haut de page

Bloquer les alias de connexion

WordPress permet d’accéder à la connexion ou au tableau de bord à partir d’alias. Par exemple, vous pouvez afficher le formulaire de connexion à l’adresse « http://monsite.fr/login ».
Lorsque l’utilisateur n’est pas connecté, et qu’il utilise un alias de tableau de bord (exemple : « http://monsite.fr/dashboard », WordPress redirige vers le formulaire de connexion.

Comme nous voulons que la demande de connexion ne puisse s’effectuer que via l’adresse que nous avons redéfinie, nous renvoyons toute tentative de les utiliser vers l’adresse de refus de connexion.

Le code gérant les alias se trouve dans le fichier « wp-includes/canonical.php » :

Modifier wp-login.php - Les alias d'accès à la connexion et à l'administration
Les alias d’accès à la connexion et à l’administration

Bloquer les alias de login

add_filter( 'login_url', 'wpdf_filtre_adresse_login', 10, 3 );

function wpdf_filtre_adresse_login( $wpdf_login_url, $wpdf_redirect, $wpdf_force_reauth ) {
    $wpdf_logins = array(
        home_url( 'wp-login.php', 'relative' ),
        home_url( 'login', 'relative' ),
        network_site_url( 'login', 'relative' ),
    );
    if ( in_array( untrailingslashit( $_SERVER['REQUEST_URI'] ), $wpdf_logins ) ) { 
        wp_redirect( WPDF_ADRESSE_CONNEXION_REFUSEE );
        exit();
    }

    return $wpdf_login_url;
}    // fin fonction wpdf_filtre_adresse_login

Ajouter la fonction « wpdf_filtre_adresse_login » au filtre « login_url » qui est appelé lorsque l’url correspond à un des alias de login :

add_filter( ‘login_url’, ‘wpdf_filtre_adresse_login‘, 10, 3 );

Les urls d’alias sont placés dans le tableau « $wpdf_logins » :

$wpdf_logins = array(
home_url( ‘wp-login.php’, ‘relative’ ),
home_url( ‘login’, ‘relative’ ),
network_site_url( ‘login’, ‘relative’ ),
);

L’adresse relative, comme l’uri retournée par « $_SERVER[‘REQUEST_URI’] »,  correspond à la partie d’url qui se situe après le nom de domaine. Par exemple, à l’url « http://localhost/demo/wp-login.php » correspond l’url relative « demo/wp-login.php ».

La fonction recherche si l’uri se trouve dans le tableau des adresses de login à filtrer, et si elle s’y trouve, la fonction redirige vers l’adresse de refus de la connexion :

if ( in_array( untrailingslashit( $_SERVER[‘REQUEST_URI’] ), $wpdf_logins ) ) {
wp_redirect( WPDF_ADRESSE_CONNEXION_REFUSEE );
exit();
}
return $wpdf_login_url;

Si l’uri ne correspond pas à un alias de connexion, la fonction retourne l’adresse passée en paramètre sans la modifier.

La fonction « untrailingslashit() » retire un éventuel caractère « / » en fin d’url car la comparaison de « in_array() » est stricte (la chaîne de caractères testée doit être exactement identique dans le tableau des valeurs à comparer).

Bloquer les alias d’administration

Ajouter au filtre « admin_url » la fonction « wpdf_filtre_adresse_admin » qui filtre les alias d’administration (« wp-admin », « dashboard » et « admin ») de la même façon que la fonction « wpdf_filtre_adresse_login » filtre les alias de connexion directe.

add_filter( 'admin_url', 'wpdf_filtre_adresse_admin', 10, 3 );

function wpdf_filtre_adresse_admin( $wpdf_login_url, $wpdf_redirect, $wpdf_force_reauth ) {
    if ( (function_exists('is_user_logged_in')) &&!( is_user_logged_in ()) ) {
        $wpdf_admins = array(
    home_url( 'wp-admin', 'relative' ),
            home_url( 'dashboard', 'relative' ),
            home_url( 'admin', 'relative' ),
            network_site_url( 'dashboard', 'relative' ),
            network_site_url( 'admin', 'relative' ),
        );
        if ( in_array( untrailingslashit( $_SERVER['REQUEST_URI'] ), $wpdf_admins ) ) {
            wp_redirect( WPDF_ADRESSE_CONNEXION_REFUSEE );
            exit();
        }
    }    //    fin test si utilisateur connecté
    return $wpdf_login_url;
}    // fin fonction wpdf_filtre_adresse_admin

Remarque sur les fonctions redéfinissables (pluggable)

« is_user_logged_in » est une fonction redéfinissable. Elle est définie dans le fichier « pluggable.php », de telle façon que si une extension (ou une extension automatique) l’a déjà définie, la définition dans le fichier « pluggable.php » n’est pas prise en compte. Cela permet de remplacer une fonction standard WordPress par une fonction personnalisée.

Pour permettre ce choix, le fichier pluggable.php est chargé après les extensions. En appelant la fonction « is_user_logged_in » dans l’extension « wpdf_deplace_connexion », il y a un risque qu’elle soit appelée alors qu’elle n’est pas encore définie. C’est par exemple le cas si une autre extension sollicite le crochet « admin_url » durant son activation.

C’est pourquoi un test de définition de « is_user_logged_in » est effectué avant d’appeler la fonction :

if ( (function_exists('is_user_logged_in')) &&!( is_user_logged_in ()) ) {

Cela peut éviter un plantage du site (appeler une fonction non définie est une erreur php fatale) et ne perturbe pas l’utilisation de la fonction « wpdf_filtre_adresse_admin » car la fonction « is_user_logged_in » n’est indéfinie que durant le processus de chargement de WordPress ».

Haut de page

Le code de l’extension (plugin)

Voici le code de l’extension. Pour l’utiliser, déposez le fichier dans le répertoire « plugins » de votre site, ou mieux, dans le répertoire « mu-plugins » pour que l’extension soit toujours activée.

<?php
/*
Plugin Name: Deplace connexion
Plugin URI:  http://dfarnier.fr/modifier-wp-login/
Description: modifier l'adresse de connexion pour éviter un piratage
Version:     4
Author:      Daniel Farnier
Author URI:  http://dfarnier.fr
License:     GPL2
License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/

//	Vérifier que l'extension est appelée depuis WordPress et non directement via internet
if ( !defined('ABSPATH') ) exit ('Faites demi-tour !');

//	définir la nouvelle adresse de connexion
define('WPDF_ADRESSE_CONNEXION', 'coucou');
//	définir l'adresse de retour quand la connexion est refusée (exemple : la page d'accueil)
define('WPDF_ADRESSE_CONNEXION_REFUSEE', network_site_url());

//	rediriger vers le fichier programme wp-login.php si la nouvelle adresse est appelée correctement
//  pour se connecter / déconnecter, réinitialiser le mot de passe
//	ou se reconnecter après une déconnexion automatique
add_action( 'init', 'wpdf_redirige_login' );

function wpdf_redirige_login()  {
	
	$wpdf_adresse_connexion = '/'.WPDF_ADRESSE_CONNEXION;	//	adresse de base

	$wpdf_patron='#' . $wpdf_adresse_connexion.'$|' . $wpdf_adresse_connexion . '/?\?action=rp&?|' . $wpdf_adresse_connexion.'/?\?loggedout=true$|' . $wpdf_adresse_connexion . '/?\?checkemail=confirm$|' . $wpdf_adresse_connexion.'/?\?checkemail=registered$|' . $wpdf_adresse_connexion . '/?\?action=lostpassword&?$|' . $wpdf_adresse_connexion . '/?\?action=lostpassword&error=expiredkey$|' . $wpdf_adresse_connexion . '/?\?action=lostpassword&error=invalidkey$|' . $wpdf_adresse_connexion . '/?\?action=resetpass$|' . $wpdf_adresse_connexion.'/?\?registration=disabled$|' . $wpdf_adresse_connexion . '/?\?action=register|' . $wpdf_adresse_connexion . '/?\?checkemail=registered$|' . $wpdf_adresse_connexion . '/?\?interim-login=1$|' . $wpdf_adresse_connexion . '/?\?redirect_to=|' . $wpdf_adresse_connexion . '\?action=lostpassword&error=expiredkey|' . $wpdf_adresse_connexion . '\?action=lostpassword&error=invalidkey|' . $wpdf_adresse_connexion . '\?registration=disabled|' . $wpdf_adresse_connexion . '/?\?action=logout&_wpnonce=#';
		
	if (preg_match($wpdf_patron, untrailingslashit( $_SERVER['REQUEST_URI'])) === 1 ) {
		error_reporting(E_ALL & ~E_NOTICE);
		require_once(ABSPATH . 'wp-login.php');
		exit();
	}	//	fin test si nouvelle url de connexion
}	//	fin fonction wpdf_redirige_login

//---------------------------------------------------------------------
//	rediriger les connexions ne venant pas de la nouvelle adresse
add_action( 'login_init', 'wpdf_refuse_connexion' );

function wpdf_refuse_connexion() {
	if ( strpos( $_SERVER['REQUEST_URI'], '/'.WPDF_ADRESSE_CONNEXION ) === false ) {
		wp_redirect( WPDF_ADRESSE_CONNEXION_REFUSEE );
		exit();
	}	// fin test si nouvelle adresse de connexion non trouvée
}	//	fin fonction wpdf_refuse_connexion


//---------------------------------------------------------------------
//	modifier l'adresse de connexion affichée sur le site (forumulaires, liens)
add_filter( 'site_url', 'wpdf_modifie_adresse_connexion', 10, 3 );
if (is_multisite()) add_filter( 'network_site_url', 'wpdf_modifie_adresse_connexion', 10, 3 );

function wpdf_modifie_adresse_connexion( $wpdf_aff_login_url, $wpdf_path, $wpdf_orig_scheme ) {

	if ( $wpdf_orig_scheme === 'login' || $wpdf_orig_scheme === 'login_post' ){
		$wpdf_aff_login_url = preg_replace( '/wp-login\.php/', WPDF_ADRESSE_CONNEXION, $wpdf_aff_login_url, 1 );
	}	//	fin test si scheme égal login ou login_post

	$wpdf_siteurl_patron = '#wp-login.php\?action=lostpassword&error=expiredkey$|wp-login.php\?action=lostpassword&error=invalidkey$|wp-login.php\?registration=disabled$#';

	if ( preg_match($wpdf_siteurl_patron, $wpdf_aff_login_url) === 1  )
		$wpdf_aff_login_url = preg_replace( '/wp-login\.php/', WPDF_ADRESSE_CONNEXION, $wpdf_aff_login_url, 1 );	
	return $wpdf_aff_login_url;
}	// fin fonction wpdf_modifie_adresse_connexion


// modifie l'adresse après demande de déconnexion ou de modification du mot de passe
add_filter ('wp_redirect', 'wpdf_redirect_mdpout', 10, 2);

function wpdf_redirect_mdpout ( $wpdf_location, $wpdf_status ) {
	$wpdf_redirect_mdpout = array (
		'wp-login.php?loggedout=true',
		'wp-login.php?checkemail=confirm',
		'wp-login.php?checkemail=registered'
	);
	if ( in_array( $wpdf_location, $wpdf_redirect_mdpout ) )
		$wpdf_location = preg_replace( '/wp-login\.php/', WPDF_ADRESSE_CONNEXION, $wpdf_location, 1 );
    return $wpdf_location;
}	// fin fonction wpdf_redirect_mdpout

//	modifie le message de bienvenue pour un nouveau site
add_filter ('update_welcome_email', 'wpdf_update_welcome_email', 10, 6);

function wpdf_update_welcome_email ( $wpdf_welcome_email, $wpdf_blog_id, $wpdf_user_id, $wpdf_password, $wpdf_title, $wpdf_meta) {
	$wpdf_welcome_email = preg_replace( '/wp-login\.php/', WPDF_ADRESSE_CONNEXION, $wpdf_welcome_email, 1 );
    return $wpdf_welcome_email;
}	// fin fonction wpdf_update_welcome_email

//-----------------------------------------------------------------------------------------------
//	renvoyer vers WPDF_ADRESSE_CONNEXION_REFUSEE si adresse = 'wp-login.php' ou 'login' 
add_filter( 'login_url', 'wpdf_filtre_adresse_login', 10, 3 );

function wpdf_filtre_adresse_login( $wpdf_login_url, $wpdf_redirect, $wpdf_force_reauth ) {
	$wpdf_logins = array(
		home_url( 'wp-login.php', 'relative' ),
		home_url( 'login', 'relative' ),
		network_site_url( 'login', 'relative' ),
	);
	if ( in_array( untrailingslashit( $_SERVER['REQUEST_URI'] ), $wpdf_logins ) ) { 
		wp_redirect( WPDF_ADRESSE_CONNEXION_REFUSEE );
		exit();
	}

	return $wpdf_login_url;
}	// fin fonction wpdf_filtre_adresse_login

//	renvoyer vers WPDF_ADRESSE_CONNEXION_REFUSEE si adresse alias d'administration
add_filter( 'admin_url', 'wpdf_filtre_adresse_admin', 10, 3 );

function wpdf_filtre_adresse_admin( $wpdf_login_url, $wpdf_redirect, $wpdf_force_reauth ) {
	if ( (function_exists('is_user_logged_in')) &&!( is_user_logged_in ()) ) {
		$wpdf_admins = array(
	home_url( 'wp-admin', 'relative' ),
			home_url( 'dashboard', 'relative' ),
			home_url( 'admin', 'relative' ),
			network_site_url( 'dashboard', 'relative' ),
			network_site_url( 'admin', 'relative' ),
		);
		if ( in_array( untrailingslashit( $_SERVER['REQUEST_URI'] ), $wpdf_admins ) ) {
			wp_redirect( WPDF_ADRESSE_CONNEXION_REFUSEE );
			exit();
		}
	}	//	fin test si utilisateur connecté
	return $wpdf_login_url;
}	// fin fonction wpdf_filtre_adresse_admin

?>

Installer l’extension

Pour installer l’extension sur votre site :

    • Cliquer sur le lien vers le fichier du code de l’extension,

      Cliquer sur le lien vers le fichier de l'extension qui déplace l'adresse de connexion
      Cliquer sur le lien vers le fichier de l’extension
    • Le fichier doit se télécharger sur votre ordinateur,
Choir "enregistrer" le fichier de l'extension (Firefox)
Enregistrer l’extension sur son ordinateur (exemple Firefox)

Suivant le paramétrage du navigateur (Firefox, Chrome, Edge…), le téléchargement peut se faire directement dans le répertoire « Téléchargement » :

Récupération du fichier de l'extension dans le répertoire "Téléchargement"
Récupération du fichier dans le répertoire « Téléchargement »

À noter : n’ouvrez le fichier que dans un éditeur de texte comme Notepad et non pas dans un traitement de texte comme Word qui ajoutera des codes de mise en forme incompréhensibles pour php.

  • Envoyer le fichier sur le site, par exemple en utilisant FileZilla;
    je vous conseille de l’installer dans le répertoire « mu-plugins » de façon à ce que l’extension soit toujours active. Pour ne plus l’utiliser, il faudra retirer le fichier du répertoire « mu-plugins ».

    Envoyer le fichier .wpdf vers le site
    Envoyer le fichier .wpdf vers le site
  • Renommer le fichier « .wpdf » « en « .php »

    Renommer le fichier de l'extension en ".php"
    Renommer le fichier de l’extension en « .php »

L’extension est en place et active.

À noter : si vous placez le ficher de l’extension dans le répertoire « plugins », vous devrez vous rendre dans l’administration du site et activer l’extension comme cela est expliqué plus haut dans cet article.

Haut de page

26 réflexions sur « Modifier l’accès à wp-login.php »

  1. Bonjour,

    Dans mes recherches, j’atterri ici. Les explications sont trop compliqués pour mon niveau, cependant ce qui m’arrive doit être en rapport avec ce tutoriel.

    J’ai tout récemment mis en place le plugin SecuPress dans sa version Pro et j’ai trop coché de cases de « sécurisation de mon site » tant est si bien que je me retrouve piégé.

    L’adresse de mon administration de mon site web se trouve redirigé sur la page d’accueil de mon site. Cette adresse sous la forme « truc.fr/xp-admin.php » est dans mes favoris. C’est ce qui me permettait d’accéder à l’admin de mon site.

    Maintenant, ce n’est plus possible.

    En sécurisant au maximum l’accès à mon site, je ne peux plus moi-même y accéder alors que je détiens mon identifiant et mon mot de passe.

    Je viens de prévenir SecuPress pour qu’ils me sorte de là et j’attend.

    Tout ça pour dire que si on ne sait pas vraiment les filtres que l’on applique, il vaut mieux s’abstenir.

    Cordialement

    Laurent

    1. Bonjour,

      J’étais sur la route toute la journée, aussi je n’ai pas pu vous répondre plus tôt.

      Comme vous avez contacté le support SecuPress, je suppose qu’ils vous ont dépanné. C’était le bon réflexe.

      Lorsqu’un plugin crée un problème sans qu’il soit possible de se connecter à l’administration pour le désactiver, il est toujours possible de le retirer du répertoire wp-content/plugins en utilisant un client FTP comme FileZilla.
      Cela « neutralisera » le plugin, vous permettra de vous connecter à l’administration par l’adresse habituelle, mais vous risquez de retrouver le problème si vous réinstallez et si vous réactivez le plugin.

      Cordialement
      Daniel Farnier

  2. Bonjour,

    Merci pour ce super tuto.

    je viens de tester le code sur mon site….

    Mais j’ai une erreur :

    Warning: call_user_func_array() expects parameter 1 to be a valid callback, function ‘disable_wplogin’ not found or invalid function name in … … /wp-includes/plugin.php on line 524

    Vous avez une petite idée 😉

  3. Pour savoir si on utilise wordpress il faut faire monsite/wp-json

    As tu une astuce pour modifier (renommer) ce lien ?

    Les pirates scrutent le web à la recherche de sites WordPress… et la c’est un très bon indice lol

    1. Il est toujours possible de rediriger une adresse de son site vers une adresse de son choix pour tromper les pirates(voir tutoriel : https://dfarnier.fr/redirections-wordpress/). Mais attention, il ne faut pas casser le fonctionnement normal de WordPress.
      Dans le cas du login, le nombre d’url à identifier est limité et n’évolue pas. Dans le cas de la json api, je crains qu’il soit difficile de distinguer la tentative de piratage de l’usage normal.

      Pour savoir si un site est en WordPress, il suffit de regarder le source et de chercher « wp-« , qui correspond notamment aux les liens vers les bibliothèques qui sont dans wp-includes et aux classes css qui commencent par wp-.

      Sur ce que j’ai pu voir en analysant des logs, la plupart des pirates attaquent avec des url précises, ils ne passent même pas par l’étape de savoir si un site est en WordPress.
      Ils ont des url qui correspondent à des failles connues, le plus souvent sur des extensions. S’ils tombent sur un site qui a la faille, donc la version de l’extension non corrigée, ils ont gagné.
      C’est pourquoi, je remplace wp-content, car les adresses utilisées sont du type « monsite/wp-content/plugins/extension_défailllante.php. Ainsi, je passe à travers toutes ces attaques car elles tapent à une mauvaise adresse.
      En revanche, si quelqu’un en veut spécifiquement à un site, il sera difficile de l’empêcher de s’apercevoir qu’il est en WordPress, et il essaiera toutes les failles qu’il connait.

  4. Bonjour… re bonjour lol
    J’ai un truc de fou… cela marche pour tout /wp-login /login /admin…
    Mais pas pour /wp-admin car dans ce cas il redirige vers la nouvelle page de connexion… qui devient en plus visible et lisible https://…/coucou?redirect_to=https%3A%2F%2Fallo-symo.fr%2Fwp-admin%2F&reauth=1

    Une petite idée ?

  5. je viens de tester sur une install propre (nouvelle)… pas de plugins, le theme de wordpress par default… uniquement le code téléchargé dans mu-plugins.

    Et cela fait toujours pareil…

  6. le comportement avec :

    wp-login -> Oups ! Cette page est introuvable.
    login -> la racine page index
    wp-admin -> la racine page indexe.
    admin -> redirection vers la nouvelle adresse de connection

    1. Je viens de retester et je n’ai pas de problème, y compris avec la 4.7.
      Cela vaut le coup d’essayer de comprendre.

      Est-ce que tu ne testerais pas en étant déjà connecté ?
      Es-tu en mono ou en multisite ?

      Utilise la page de contact pour me donner ton adresse mail. Je te renvoie le code que j’utilise pour être sûr que tu as le bon code.

  7. Bonjour je n’utilise pas le multisite, je suis en mono site et non je ne suis pas connecté 🙁

    J’avais testé le code il y a quelques temps il fonctionnait… mais impossible de le remettre correctement… alors que je n’ai rien changé…

    J’ai tout réinstallé à Zéro (sans plugins, nouvelle install, nouvelle base… seul le dossier FTP racine est le même).

    NB : Dans mon dossier j’avais un fichier bizare style WP_SITEMAP_XML.php, j’ai tout supprimé mais chaque fois que je réinstalle (sur base nouvelle et réinstallation de wordpress) l’url /wp-login ne fonctionne plus j’ai une message d’erreur… (avant même de mettre ton script)

    Je suis obligé de definir WP_HOME et’WP_SITEURL dans le fichier config

  8. Le problème tourne autour des redirections. Il faudrait regarder le fichier .htaccess.

    Est-ce que tu sais utiliser le mode debug de WordPress pour voir s’il y a une erreur dans la log ?

    Tu peux aussi regarder le mode debug du nvaigateur pour voir s’il y a une redirection.

    Bon courage

  9. je n’ai que le htaccess de base

    # BEGIN WordPress

    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.php$ – [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]

    # END WordPress

    1. Est-ce que le mode debug de WordPress permet d’obtenir des informations dans le fichier log ?

      Il faut rajouter le code suivant dans wp-config.php:

      // permet de récupérer toutes les erreurs php, et autres messages wordpress
      define(‘WP_DEBUG’, true);
      define(‘SCRIPT_DEBUG’, true);

      // Demander à WordPress d’inscrire les messages d’erreurs dans le fichier debug.log
      define(‘WP_DEBUG_LOG’, true);

      // Ne pas afficher les erreurs à l’écran
      define(‘WP_DEBUG_DISPLAY’, false);
      @ini_set(‘display_errors’, 1);

      Les messages d’erreurs doivent s’afficher dans le fichier debug.log qui se crée, s’il y a une erreur, dans le répertoire wp-content.

      Essaie les diverses connexions et regarde dans le fichier debug.log s’il y a message d’erreur.

  10. oups si
    get_bloginfo est appelé avec un argument qui est déprécié depuis la version 2.2.0 ! L’option home est obsolète pour l’ensemble des fonctions bloginfo(). Utilisez plutôt l’option url. in /home/www/…./wp-includes/functions.php on line 3975

  11. je viens de tester sur un autre site… plus ancien et voici la ligne d’erreur :

    Warning: Cannot modify header information – headers already sent by (output started at /home/www/…/wp-content/mu-plugins/test.php:1) in /home/www/…/wp-includes/pluggable.php on line 1167

    1. Fichier de l’extension corrigé.
      Merci, ça évitera à d’autres visiteurs de tomber sur le problème.
      ==> l’extension ne nécessite aucune modification de .htaccess, tout se fait dans WordPress (c’est volotaire)

  12. je t’ai communiqué mon mail pour le fichier je testerai encore sur une nouvelle installation… si tu peux me mettre ton htaccess il y a peut un truc en en plus dans ton htaccess que celui de base pour que cela fonctionne 🙁

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.