Salta al contenuto principale
Sistemi Attivi
WP Planet — WordPress Cloud & Managed Services
Torna al MagazineSicurezza

Two-factor authentication WordPress: perché la password non basta più

27 Ott 2026 — 12:45 8 min di lettura
Two-factor authentication WordPress: perché la password non basta più

Il brute force non è più il vettore principale — le credenziali rubate sì. La password, anche forte, è un singolo fattore che può essere compromesso. Il 2FA è l'unica difesa che ferma l'accesso anche quando la password è trapelata. Come implementarlo senza frustrare gli utenti legittimi.

Il modo in cui i siti WordPress vengono compromessi è cambiato. Dieci anni fa era quasi tutto brute force — bot che provavano migliaia di password su wp-login.php. Oggi il brute force è ancora attivo, ma il vettore principale è diverso: credenziali rubate. Password che finiscono in database trapelati da altri siti, phishing mirato, infostealer che rubano le credenziali salvate nel browser. La password, anche forte, è un singolo fattore — e un singolo fattore può sempre essere compromesso.

Il two-factor authentication (2FA) aggiunge un secondo fattore: qualcosa che sai (password) più qualcosa che hai (il telefono, una chiave hardware). Anche se la password viene rubata, l'attaccante non può accedere senza il secondo fattore. È l'unica difesa che rimane efficace quando il primo fattore è compromesso — ed è per questo che è diventato uno standard de facto per l'accesso amministrativo.

I tre tipi di 2FA (e quale scegliere)

Il 2FA non è tutto uguale. Ci sono tre metodi principali, con livelli di sicurezza e usabilità diversi. Il primo è il 2FA via SMS: il sito invia un codice via SMS. È il più facile da implementare ma il meno sicuro — il SIM swapping permette a un attaccante di prendere controllo del numero di telefono e ricevere i codici. Google e Microsoft hanno deprecato il 2FA via SMS per i loro account, e per buone ragioni.

Il secondo è il 2FA via app authenticator (Google Authenticator, Authy, Microsoft Authenticator): l'app genera un codice a sei cifre che cambia ogni 30 secondi. Non dipende dal operatore telefonico, non è vulnerabile al SIM swapping, ed è gratuito. È il metodo che raccomandiamo per la maggior parte dei siti WordPress.

Il terzo è la chiave hardware (YubiKey, Titan): un dispositivo fisico che devi toccare per autenticarti. È il più sicuro — immune al phishing perché la chiave verifica il dominio del sito — ma ha un costo (30-50€ per chiave) e richiede che l'utente la abbia fisicamente con sé. Per account amministrativi di siti ad alto valore, è la scelta migliore.

Implementazione: il pattern che usiamo

Per implementare il 2FA su WordPress, il modo più affidabile è un plugin dedicato. Ma se vuoi implementarlo in codice custom (es. per un'integrazione specifica), ecco il pattern con un'app authenticator e la libreria PHP per TOTP:

wp-config.php
<?php
// Implementazione 2FA TOTP custom (semplificata)
// Richiede la libreria PHP otphp (composer require spomky-labs/otphp)

use OTPHP\TOTP;

// 1. Genera un secret per l'utente (una volta sola, al setup)
function wp_planet_generate_2fa_secret( $user_id ) {
    $totp = TOTP::generate();
    $secret = $totp->getSecret();
    update_user_meta( $user_id, 'wp_planet_2fa_secret', $secret );
    update_user_meta( $user_id, 'wp_planet_2fa_enabled', true );

    // Genera l'URI per il QR code
    $totp->setLabel( get_userdata( $user_id )->user_email );
    $totp->setIssuer( get_bloginfo( 'name' ) );
    return $totp->getProvisioningUri();
}

// 2. Verifica il codice inserito dall'utente al login
function wp_planet_verify_2fa_code( $user_id, $code ) {
    $secret = get_user_meta( $user_id, 'wp_planet_2fa_secret', true );
    if ( ! $secret ) return false;

    $totp = TOTP::createFromSecret( $secret );
    return $totp->verify( $code );
}

// 3. Hook nel processo di login: richiedi 2FA dopo la password
add_filter( 'authenticate', function( $user, $username, $password ) {
    if ( is_wp_error( $user ) || ! $user instanceof WP_User ) {
        return $user;
    }

    $enabled = get_user_meta( $user->ID, 'wp_planet_2fa_enabled', true );
    if ( ! $enabled ) return $user;

    // Se il 2FA non è stato ancora inviato, ferma l'autenticazione
    // e mostra il form del codice 2FA
    $two_factor_code = $_POST['two_factor_code'] ?? '';
    if ( empty( $two_factor_code ) ) {
        // Mostra il form 2FA (gestito dal template)
        return new WP_Error(
            'two_factor_required',
            'Inserisci il codice 2FA dalla tua app authenticator.'
        );
    }

    if ( ! wp_planet_verify_2fa_code( $user->ID, $two_factor_code ) ) {
        return new WP_Error(
            'invalid_two_factor',
            'Codice 2FA non valido. Riprova.'
        );
    }

    return $user;
}, 30, 3 );
Nota: Questa è un'implementazione semplificata. Per produzione, usa un plugin consolidato come Two Factor (di WordPress.org) o Wordfence Login Security. La logica custom va gestita con attenzione: il secret deve essere salvato cifrato, i codici di backup generati per il recupero, e il rate limiting applicato ai tentativi 2FA per evitare brute force sul codice a 6 cifre.

Codici di backup: il piano B che ti salva

Il rischio del 2FA è perdere l'accesso al secondo fattore: il telefono si rompe, l'app viene disinstallata, la chiave hardware si perde. Senza un piano di recupero, l'utente è bloccato fuori dal suo account — e per un amministratore WordPress, questo significa bloccato fuori dal sito. La soluzione sono i codici di backup: 10 codici monouso generati al setup del 2FA, da stampare e conservare in luogo sicuro.

wp-config.php
<?php
// Generazione di codici di backup monouso
function wp_planet_generate_backup_codes( $user_id ) {
    $codes = array();
    for ( $i = 0; $i < 10; $i++ ) {
        // Codice di 8 caratteri alfanumerici
        $codes[] = strtoupper( wp_generate_password( 8, false ) );
    }

    // Salva i codici come hash (mai in chiaro)
    $hashed = array_map( 'wp_hash_password', $codes );
    update_user_meta( $user_id, 'wp_planet_2fa_backup_codes', $hashed );

    return $codes; // Mostra all'utente una volta sola
}

// Verifica un codice di backup (e lo consuma)
function wp_planet_verify_backup_code( $user_id, $code ) {
    $hashed = get_user_meta( $user_id, 'wp_planet_2fa_backup_codes', true );
    if ( ! is_array( $hashed ) ) return false;

    foreach ( $hashed as $i => $hash ) {
        if ( wp_check_password( $code, $hash ) ) {
            // Consuma il codice (rimuovilo dalla lista)
            unset( $hashed[ $i ] );
            update_user_meta( $user_id, 'wp_planet_2fa_backup_codes', array_values( $hashed ) );
            return true;
        }
    }
    return false;
}
Nota: I codici di backup devono essere salvati come hash, mai in chiaro nel database. Se il database viene compromesso, i codici in chiaro sarebbero utilizzabili. Ogni codice è monouso — una volta usato, viene rimosso. L'utente deve poter rigenerare i codici se li esaurisce o li perde.

Chi deve avere il 2FA (e chi no)

Il 2FA su WordPress dovrebbe essere obbligatorio per tutti gli utenti con ruolo amministrativo o che possono pubblicare/modificare contenuti. Per i ruoli inferiori (subscriber, customer in WooCommerce), il 2FA è opzionale — il rischio di compromissione è minore e l'attrito per l'utente non è giustificato. La regola: se l'account può modificare il sito o accedere a dati sensibili, il 2FA è obbligatorio.

Il 2FA non è un lusso — è la differenza tra un sito che resiste alle credenziali rubate e uno che cede al primo database trapelato. La password, per quanto forte, è un singolo punto di failure. Il 2FA lo raddoppia, e per un sito aziendale, quel raddoppio è la differenza tra una giornata normale e una settimana di emergenza.

Audit di sicurezza

Verifica la sicurezza del tuo WordPress prima che diventi un'emergenza.

Un audit di sicurezza individua le falle, i plugin vulnerabili e le configurazioni deboli prima che qualcuno le sfrutti.

Audit di sicurezza
Condividi