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ändardata, filer och administrativa 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ändare ä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 pluginet 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ändarroll. Det gör lösningen mer flexibel och fungerar bättre på webbplatser där roller och behörigheter har anpassats.
2. Skydda formulär med nonce
En nonce hjälper till att skydda formulär och administrativa åtgärder mot CSRF-attacker, där en användare 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ändaren 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 pluginet behöver köra egna databasfrågor ska du aldrig bygga SQL genom att klistra ihop värden direkt från användaren. 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 pluginet 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ändare 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ändarinmatning.
9. Separera säkerhetskontroller 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äkerhetskontroller 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 pluginet 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 administrativa å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 pluginets arkitektur. Behörighetskontroller, 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 utvecklingsmiljön – och faktiskt är tryggt att köra på en webbplats i produktion.
