Plugin­utveckling

Så bygger du ett säkert plugin till WordPress

Säkerhet behöver finnas med från första raden kod. Här går vi igenom de viktigaste principerna för att bygga WordPress-plugin som är säkra, robusta och redo för produkt­ion.

Programmeringskod på en datorskärm i mörk teknisk miljö

Att bygga ett WordPress-plugin handlar inte bara om funktionalitet. Ett plugin kör kod inne i WordPress och kan därför få tillgång till databasen, användar­data, filer och admin­istrativa funktioner. Därför behöver säkerheten finnas med från första raden kod – inte läggas till i efterhand.

I den här guiden går vi igenom de viktigaste principerna för att bygga ett säkert WordPress-plugin, med konkreta exempel som går att använda i riktiga projekt.

1. Kontrollera alltid behörigheter

Bara för att en användar­e är inloggad betyder det inte att personen ska få göra vad som helst. Kontrollera därför alltid vilken behörighet som krävs innan plugin­et utför en känslig åtgärd.

if ( ! current_user_can( 'manage_options' ) ) {    wp_die( 'Du har inte behörighet att utföra den här åtgärden.' );}

Använd WordPress capabilities i stället för att kontrollera en viss användar­roll. Det gör lösningen mer flexibel och fungerar bättre på webb­platser där roller och behörigheter har anpassats.

2. Skydda formulär med nonce

En nonce hjälper till att skydda formulär och admin­istrativa åtgärder mot CSRF-attacker, där en användar­e annars kan luras att utföra en åtgärd utan att veta om det.

wp_nonce_field( 'my_plugin_save_settings', 'my_plugin_nonce' );

När formuläret tas emot verifierar du värdet innan något sparas:

if (    ! isset( $_POST['my_plugin_nonce'] ) ||    ! wp_verify_nonce(        sanitize_text_field( wp_unslash( $_POST['my_plugin_nonce'] ) ),        'my_plugin_save_settings'    )) {    wp_die( 'Ogiltig säkerhetskontroll.' );}

3. Sanera data som kommer in

All data som kommer från användar­en ska betraktas som osäker tills den har kontrollerats. Det gäller formulärfält, query-parametrar, REST-anrop och andra externa datakällor.

WordPress har flera färdiga funktioner för detta:

  • sanitize_text_field() för vanlig text.
  • sanitize_email() för e-postadresser.
  • esc_url_raw() för URL:er som ska sparas.
  • absint() för positiva heltal.
  • sanitize_key() för nycklar och sluggar.

$name = isset( $_POST['name'] )    ? sanitize_text_field( wp_unslash( $_POST['name'] ) )    : '';

4. Escapa data när den skrivs ut

Sanering sker när data kommer in. Escaping sker när data skrivs ut. Det är två olika skydd och båda behövs.

<p><?php echo esc_html( $name ); ?></p><a href="<?php echo esc_url( $url ); ?>">    Läs mer</a>

Välj escaping-funktion efter sammanhanget. För HTML-attribut används till exempel esc_attr(), medan vanlig text skrivs ut med esc_html().

5. Använd WordPress databas-API

Om plugin­et behöver köra egna databasfrågor ska du aldrig bygga SQL genom att klistra ihop värden direkt från användar­en. Använd i stället $wpdb->prepare().

global $wpdb;$result = $wpdb->get_row(    $wpdb->prepare(        "SELECT * FROM {$wpdb->prefix}my_table WHERE id = %d",        $id    ));

I många fall är det ännu bättre att använda WordPress inbyggda API:er, exempelvis WP_Query, Options API, Metadata API eller REST API, eftersom de redan hanterar mycket av säkerheten åt dig.

6. Skydda AJAX och REST API

AJAX- och REST-endpoints är vanliga angreppspunkter eftersom de ofta kan anropas direkt utifrån. Därför behöver varje endpoint kontrollera både behörighet och indata.

För REST API bör du alltid definiera en permission_callback:

register_rest_route(    'my-plugin/v1',    '/settings',    [        'methods'             => 'POST',        'callback'            => 'my_plugin_save_settings',        'permission_callback' => function () {            return current_user_can( 'manage_options' );        },    ]);

Undvik att använda __return_true som standard för endpoints som hanterar känsliga uppgifter eller ändrar data.

7. Lita inte på filnamn och filtyper

Om plugin­et hanterar filuppladdningar behöver du vara extra försiktig. Kontrollera filtyp, MIME-typ och använd WordPress egna funktioner för uppladdningar i stället för att flytta filer manuellt.

Begränsa vilka filtyper som tillåts och utgå aldrig från att ett filnamn beskriver filens verkliga innehåll.

8. Undvik onödigt kraftfull kod

Ett säkert plugin ska göra så lite som möjligt med så små behörigheter som möjligt. Undvik funktioner som exekverar dynamisk PHP-kod, skriver godtyckliga filer eller ger användar­e fler rättigheter än de behöver.

Var särskilt försiktig med funktioner som eval(), dynamiska includes, rå SQL och kod som bygger filvägar från användar­inmatning.

9. Separera säkerhets­kontroller från affärslogik

Det blir enklare att granska och underhålla koden om du har en tydlig struktur. En bra princip är att göra säkerhets­kontroller tidigt i varje request och avsluta direkt om något inte är tillåtet.

Exempelvis:

function my_plugin_handle_save() {    if ( ! current_user_can( 'manage_options' ) ) {        wp_die( 'Otillåten åtgärd.' );    }    check_admin_referer( 'my_plugin_save' );    $value = isset( $_POST['value'] )        ? sanitize_text_field( wp_unslash( $_POST['value'] ) )        : '';    update_option( 'my_plugin_value', $value );}

10. Testa som om du försökte angripa ditt eget plugin

När plugin­et fungerar är arbetet inte klart. Testa även vad som händer när någon skickar oväntade värden, manipulerar URL-parametrar, försöker anropa endpoints utan rätt behörighet eller skickar HTML och JavaScript i textfält.

Kontrollera bland annat:

  • Kan en prenumerant utföra admin­istrativa åtgärder?
  • Kan en nonce återanvändas där den inte borde gälla?
  • Kan HTML eller JavaScript sparas i ett fält som bara ska innehålla text?
  • Kan en REST-route användas utan autentisering?
  • Kan en SQL-fråga påverkas genom manipulerad indata?
  • Kan någon komma åt filer utanför den avsedda katalogen?

Säkerhet är en del av arkitekturen

Det viktigaste är att se säkerhet som en del av plugin­ets arkitektur. Behörighets­kontroller, nonce-skydd, sanering, escaping och säkra API-anrop ska finnas med från början.

Ett välbyggt WordPress-plugin ska inte bara fungera när allt går rätt. Det ska också reagera säkert när någon skickar felaktiga, oväntade eller avsiktligt manipulerade värden.

Det är den skillnaden som gör att ett plugin känns stabilt i utvecklings­miljön – och faktiskt är tryggt att köra på en webb­plats i produkt­ion.