Qu'est-ce que le broken access control et comment affecte-t-il WordPress ?

Le broken access control (contrôle d’accès défaillant) est une vulnérabilité de sécurité qui se produit lorsqu’un site web ne gère pas correctement les permissions des utilisateurs, permettant ainsi à des attaquants d’accéder à des informations ou d’exécuter des actions sans autorisation. Dans WordPress, cela peut se manifester par l’absence de vérifications de permissions ou de nonce sur les hooks et les fonctions, exposant ainsi des données sensibles ou des fonctionnalités critiques.

Comment fonctionne le broken access control dans WordPress ?

Dans WordPress, les hooks et les fonctions utilisés dans les plugins ou les thèmes ne sont pas sécurisés par défaut. Il revient au développeur de vérifier manuellement les permissions et de valider les requêtes. Par exemple, la fonction current_user_can permet de s’assurer qu’un utilisateur a les droits nécessaires pour exécuter une action, tandis que wp_verify_nonce et les fonctions associées (check_admin_referer, check_ajax_referer) valident les requêtes pour prévenir les attaques de type CSRF (Cross-Site Request Forgery).

Si ces vérifications ne sont pas mises en place, les utilisateurs malveillants peuvent exploiter ces failles pour accéder à des informations ou exécuter des actions critiques via des requêtes non autorisées.

Exemples de hooks vulnérables dans WordPress

Voici quelques exemples de hooks WordPress qui, s’ils ne sont pas sécurisés correctement, peuvent être exploités pour accéder à des fonctionnalités sensibles.

Exemple du hook init

add_action("wp_loaded", "wpa_check_if_update");
function wpa_check_if_update(){
if (isset($_GET["update_option"])) {
update_option("user_custom_data", sanitize_text_field($_GET["custom_data"]));
}
}

Exploitation : Un attaquant peut manipuler l’URL pour exécuter la fonction d’update sans être authentifié. Il suffit de visiter une URL comme suit :

curl <WORDPRESS_BASE_URL>/?update_option=1&custom_data=malicious

Exemple du hook admin_menu

Dans cet exemple, le hook admin_menu est utilisé pour déclencher une fonction qui supprime une option spécifique d’un menu d’administration. Sans vérification de permission (current_user_can) et sans nonce pour authentifier la requête, ce code est vulnérable aux attaques.

add_action("admin_menu", "wpa_remove_admin_menu_option");
function wpa_remove_admin_menu_option(){
if (isset($_POST["remove_option"])) {
delete_option("wpa_custom_menu_option");
}
}

Exploitation : Une requête POST pourrait facilement être envoyée par un attaquant pour supprimer une option, sans nécessiter de connexion :

curl <WORDPRESS_BASE_URL>/wp-admin/admin-post.php?action=wpa_remove_admin_option -d "remove_option=1"

Exemple du hook wp_ajax_wpa_update_post

Ici, nous utilisons le hook wp_ajax_wpa_update_post pour une requête AJAX permettant de mettre à jour les métadonnées d’un post. Sans validation des permissions avec current_user_can, même un utilisateur authentifié de bas niveau pourrait modifier n’importe quel contenu.

add_action("wp_ajax_wpa_update_post", "wpa_update_post_data");
function wpa_update_post_data(){
if (isset($_POST["update_data"])) {
$post_id = get_post($_POST["post_id"]);
update_post_meta($post_id, "custom_meta_data", sanitize_text_field($_POST["custom_data"]));
}
}

Exploitation : Un simple utilisateur authentifié (même un abonné) pourrait exécuter une requête AJAX pour mettre à jour les métadonnées de n’importe quel post :

curl <WORDPRESS_BASE_URL>/wp-admin/admin-ajax.php?action=wpa_update_post -d "post_id=1&custom_data=new_data"

Exemple du hook wp_ajax_nopriv_wpa_toggle_feature

Cet exemple montre une fonction utilisant le hook wp_ajax_nopriv_wpa_toggle_feature, qui permet aux utilisateurs non authentifiés de modifier une option spécifique. Sans vérification supplémentaire, cette fonction est vulnérable à des attaques, car n’importe qui peut déclencher la mise à jour des options.

add_action("wp_ajax_nopriv_wpa_toggle_feature", "wpa_toggle_feature_option");
function wpa_toggle_feature_option(){
if ($_POST["toggle_feature"] === "on") {
update_option("wpa_custom_feature", 1);
} else {
update_option("wpa_custom_feature", 0);
}
}

Exploitation : N’importe quel utilisateur non authentifié peut envoyer une requête POST pour activer ou désactiver une fonctionnalité sans aucune validation.

curl <WORDPRESS_BASE_URL>/wp-admin/admin-ajax.php?action=wpa_toggle_feature -d "toggle_feature=on"

Exemple d’une route REST API vulnérable

Dans cet exemple, une route REST personnalisée est enregistrée, permettant de supprimer un utilisateur via une requête API. Le callback wpa_delete_author_user utilise une mauvaise configuration du permission_callback, ce qui rend cette route accessible à tout utilisateur sans aucune vérification.

add_action('rest_api_init', function () {  
register_rest_route('wpa/v1', '/delete/author', array(
'methods' => 'POST',
'callback' => 'wpa_delete_author_user',
'permission_callback' => '__return_true',
));
});

function wpa_delete_author_user($request){
$params = $request->get_params();
wp_delete_user(intval($params["user_id"]));
}

Exploitation : N’importe quel utilisateur, même non authentifié, peut envoyer une requête POST à l’API REST et supprimer un utilisateur.

curl <WORDPRESS_BASE_URL>/wp-json/wpa/v1/delete/author -d "user_id=1"

Comment sécuriser les hooks et fonctions dans WordPress avec des bonnes pratiques

Pour éviter les vulnérabilités de Broken Access Control, il est crucial de mettre en place des vérifications appropriées des permissions et des nonces dans vos fonctions.

  1. Vérification des permissions avec current_user_can : cette fonction assure que l’utilisateur a les droits nécessaires pour effectuer une action. Sans cela, des utilisateurs malveillants pourraient accéder à des fonctionnalités restreintes.Exemple sécurisé :
    if (current_user_can('manage_options')) {
    // Code sécurisé
    }
  2. Vérification des nonces avec wp_verify_nonce : l’utilisation des nonces permet de valider l’authenticité des requêtes. Cela protège vos actions contre les attaques CSRF.Exemple sécurisé :
    if (isset($_POST['nonce']) && wp_verify_nonce($_POST['nonce'], 'wpa_secure_nonce')) {
    // Requête sécurisée
    }
  3. Validation des requêtes pour les routes API : lors de la création d’une route API, il est essentiel d’utiliser un permission_callback adéquat qui vérifie les droits des utilisateurs avant d’exécuter une action.Exemple sécurisé :
    add_action('rest_api_init', function () {  
    register_rest_route('wpa/v1', '/delete/author', array(
    'methods' => 'POST',
    'callback' => 'wpa_delete_author_user',
    'permission_callback' => 'wpa_check_user_permissions',
    ));
    });

    function wpa_check_user_permissions() {
    return current_user_can('delete_users');
    }
Consultez aussi d’autres définitions

Vous souhaitez travailler avec notre agence ?