Introduksjon: AI-løftet vs. WordPress-realiteten
Å bruke store språkmodeller (LLMer) som GPT-4, Claude 3.5 Sonnet eller Gemini Pro til å skrive WordPress-plugin-kode har blitt en vanlig praksis for både utviklere og nettstedseiere. Løftet er utrolig tiltalende: beskriv den nødvendige funksjonaliteten på vanlig norsk, og AI genererer en klar-til-bruk PHP-fil på sekunder.
Problemet er imidlertid at språkmodeller utmerker seg på syntaks og struktur, men mangler operasjonell kontekst og en reell forståelse av sikkerhetsprinsipper i WordPress-økosystemet. Trent på enorme datasett med offentlig kode, arver de millioner av utdaterte, usikre og dårlig skrevne plugins publisert i løpet av de siste to tiårene. Som et resultat produserer AI ofte kode som er syntaktisk feilfri og funksjonell, men full av kritiske sikkerhetssårbarheter under panseret.
Som WordPress-utviklere må vi ta i bruk en streng “Zero Trust”-holdning overfor all kode skrevet av en AI. Denne guiden bryter ned de fem vanligste sikkerhetsfeilene vi observerer under revisjoner av AI-generert plugin-kode, og illustrerer dem med sårbare PHP-snutter ved siden av sikre, produksjonsklare refaktoreringer som samsvarer med WordPress Coding Standards (WPCS).
1. Feilaktig bruk av is_admin() for adgangskontroll
Kanskje den vanligste logiske feilen AI gjør når den prøver å sikre et endepunkt, er å stole på funksjonen is_admin() for å begrense adgangen til administratorer.
Hvorfor det mislykkes
Til tross for navnet, verifiserer ikke is_admin() om den nåværende innloggede brukeren er en administrator. Den sjekker kun om den gjeldende forespørselen gjelder en administrasjonsside (som enhver URL som starter med /wp-admin/).
Hver AJAX-forespørsel sendt til /wp-admin/admin-ajax.php - enten den er initiert av en administrator, en innlogget abonnent med minimale rettigheter, eller en uautentisert anonym besøkende - vil føre til at is_admin() returnerer true.
Sårbar AI-generert kode:
// En AI-generert hook for å lagre innstillinger
add_action( 'admin_init', 'ai_save_plugin_settings' );
function ai_save_plugin_settings() {
// AI antar feilaktig at dette begrenser adgangen til administratorer
if ( is_admin() ) {
if ( isset( $_POST['my_plugin_option'] ) ) {
update_option( 'my_plugin_option', $_POST['my_plugin_option'] );
}
}
}
Sikker kode:
For å verifisere de faktiske rettighetene til den innloggede brukeren, må du bruke funksjonen current_user_can(), og sende inn en spesifikk brukerrettighet i stedet for et rollenavn, for eksempel manage_options.
add_action( 'admin_init', 'secure_save_plugin_settings' );
function secure_save_plugin_settings() {
// 1. Verifiser den nåværende brukerens faktiske rettigheter
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'Du har ikke rettighet til å utføre denne handlingen.', 'secure-plugin' ) );
}
if ( isset( $_POST['my_plugin_option'] ) ) {
// Bruk sanitysering på inndata (se avsnitt 4)
$sanitized_value = sanitize_text_field( wp_unslash( $_POST['my_plugin_option'] ) );
update_option( 'my_plugin_option', $sanitized_value );
}
}
2. Komplett utelatelse av nonce-verifisering (CSRF)
Cross-Site Request Forgery (CSRF)-angrep lurer en autentisert brukers nettleser (f.eks. en administrator) til å utføre uautoriserte handlinger på et nettsted de er logget inn på. WordPress bruker kryptografiske token kalt nonces for å beskytte mot CSRF.
AI-generatorer utelater ofte opprettelse og verifisering av nonces i admin-skjemaer, AJAX-handlere og tilpassede REST API-endepunkter. Dette skjer fordi implementering av nonces krever koordinering av frontend-rendringslaget (HTML-skjemaet som inneholder nonce-feltet) med backend-prosesseringskontrolleren, noe som er vanskelig for LLMer å samkjøre på tvers av frakoblede kodegenereringer.
Sårbar AI-generert AJAX-handler:
// AI-generert AJAX-endepunktregistrering
add_action( 'wp_ajax_ai_delete_post', 'ai_delete_post_handler' );
function ai_delete_post_handler() {
// AI sjekker rettigheter, men ignorerer CSRF fullstendig (ingen nonce-sjekk)
if ( ! current_user_can( 'delete_posts' ) ) {
wp_send_json_error( 'Uautorisert.' );
}
$post_id = intval( $_POST['post_id'] );
wp_delete_post( $post_id );
wp_send_json_success( 'Innlegg slettet.' );
}
Sikker kode:
Skjemaet må generere et nonce-felt ved hjelp av wp_nonce_field(), og den mottakende PHP-kontrolleren må verifisere tokenet ved hjelp av check_ajax_referer() eller wp_verify_nonce().
// I skjemaets rendringsfil eller javascript-payload:
// wp_nonce_field( 'delete_post_action', 'my_nonce_field' );
// Registrering av sikker AJAX-handler
add_action( 'wp_ajax_secure_delete_post', 'secure_delete_post_handler' );
function secure_delete_post_handler() {
// 1. Verifiser CSRF-token tidlig
check_ajax_referer( 'delete_post_action', 'my_nonce_field' );
// 2. Verifiser brukerrettigheter
if ( ! current_user_can( 'delete_posts' ) ) {
wp_send_json_error( 'Uautorisert.' );
}
// 3. Valider og typiser inndatavariabler
if ( ! isset( $_POST['post_id'] ) ) {
wp_send_json_error( 'Mangler innleggs-ID.' );
}
$post_id = absint( $_POST['post_id'] );
if ( wp_delete_post( $post_id ) ) {
wp_send_json_success( 'Innlegget ble slettet.' );
} else {
wp_send_json_error( 'Feil under sletting av innlegget.' );
}
}
3. SQL-injeksjonssårbarheter i $wpdb-spørringer
Når en plugin samhandler direkte med databasen i stedet for å bruke den opprinnelige WP_Query-wrapperen, bruker den det globale objektet $wpdb. Dessverre konstruerer LLMer ofte rå SQL-strenger ved direkte sammenslåing av brukerleverte variabler ($_POST, $_GET) i stedet for å parametrisere spørringen.
Hvorfor det er farlig
Å slå sammen rå variabler direkte inn i databasespørringer lar en angriper manipulere spørrestrukturen. Dette kan føre til uautorisert datagjenvinning (som hashede brukerpassord), sletting av databasen, eller eskalering av administratorrettigheter.
Sårbar AI-generert spørring:
// Brukersøkfunksjon generert av AI
function ai_find_users_by_city( $city_name ) {
global $wpdb;
// Kritisk feil: direkte sammenslåing av spørrevariabelen
$query = "SELECT * FROM {$wpdb->prefix}custom_users WHERE city = '" . $city_name . "'";
return $wpdb->get_results( $query );
}
Sikker kode:
Ingen rå variabler skal noen gang skrives direkte inn i SQL-strenger. Bruk i stedet metoden $wpdb->prepare(), som fungerer som en parametrisert spørremotor, typiserer og escaper verdier ved hjelp av formatspesifikasjoner (%s for strenger, %d for heltall, %f for desimaltall).
function secure_find_users_by_city( $city_name ) {
global $wpdb;
// 1. Bruk prepare() med formatspesifikasjoner
$query = $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}custom_users WHERE city = %s",
$city_name
);
return $wpdb->get_results( $query );
}
Merk: Hvis variabelen $city_name kommer direkte fra brukerinput, må den fortsatt sanityseres med sanitize_text_field() før databasebehandling.
4. Manglende sanitysering på inndata og escaping på utdata (XSS)
Cross-Site Scripting (XSS) er en av de vanligste sårbarhetene i WordPress-plugins. Det lar ondsinnet JavaScript-kode lagres i databasen eller speiles dynamisk, og kjøres i nettleseren til intetanende besøkende.
AI-modeller forveksler ofte sanitysering (rensing av data på vei inn) med escaping (sikring av data på vei ut). Selv om AI sanityserer inndata, viser den ofte variabler i maler uten å escape dem først, noe som etterlater nettstedet åpent for lagret XSS.
Sårbar AI-generert rendring:
// Feedback-løkke skrevet av AI
function ai_display_user_feedback() {
$feedbacks = get_option( 'ai_user_feedback_list', [] );
echo '<div class="feedback-list">';
foreach ( $feedbacks as $feedback ) {
// Kritisk feil: rå utdata uten escaping
echo '<p class="feedback-item">' . $feedback['user_comment'] . '</p>';
}
echo '</div>';
}
Sikker kode:
Følg den grunnleggende WordPress-regelen: Sanitize Early, Escape Late (sanityser inndatavariabler umiddelbart; escape utdata umiddelbart før de sendes til nettleseren).
Velg riktig escaping-funksjon for konteksten:
esc_html()- for standard tekstnoder i HTML-elementer.esc_attr()- for utdata i HTML-attributtverdier.esc_url()- for utdata av lenker.wp_kses()- når du må tillate spesifikke, sikre HTML-tagger (som strong, anchors).
function secure_display_user_feedback() {
$feedbacks = get_option( 'secure_user_feedback_list', [] );
echo '<div class="feedback-list">';
foreach ( $feedbacks as $feedback ) {
$comment = isset( $feedback['user_comment'] ) ? $feedback['user_comment'] : '';
// 1. Escape utdata kontekstuelt umiddelbart før rendring
echo '<p class="feedback-item">';
echo esc_html( $comment );
echo '</p>';
}
echo '</div>';
}
5. Farlig filopplasting (Arbitrary File Upload)
Å tillate brukere å laste opp filer (som vedlegg i kontaktskjemaer eller opplasting av avatarer) er en av operasjonene med høyest risiko på et nettsted. En feil her lar angripere laste opp en .php-fil, noe som resulterer i ekstern kjøring av kode (RCE) og fullstendig serverkompromittering.
AI-genererte filbehandlere stoler ofte på opprinnelige PHP-kommandoer som move_uploaded_file() kombinert med svake filendelsessjekker (som enkel strengmatching), som er trivielle for angripere å omgå (f.eks. opplasting av filer med navnet malicious.php.jpg eller bruk av alternative etternavn som .phtml).
Sårbar AI-generert filopplasting:
// Opplastingsbehandler skrevet av AI
function ai_handle_avatar_upload() {
if ( isset( $_FILES['avatar'] ) ) {
$file_name = $_FILES['avatar']['name'];
$ext = pathinfo( $file_name, PATHINFO_EXTENSION );
// AI antar at denne filendelsessjekken er sikker
if ( in_array( $ext, ['jpg', 'jpeg', 'png'] ) ) {
$target = wp_upload_dir()['path'] . '/' . $file_name;
move_uploaded_file( $_FILES['avatar']['tmp_name'], $target );
}
}
}
Sikker kode:
Bruk aldri opprinnelig PHP move_uploaded_file() i WordPress. Bruk i stedet kjernefunksjonen wp_handle_upload(). Den utfører en robust MIME-type-sjekk (verifiserer filens faktiske signatur, ikke bare navnet), validerer opplastingsstatusen og integreres med WordPress-rettighetssystemet.
function secure_handle_avatar_upload() {
// 1. Valider CSRF-tokenet
if ( ! isset( $_POST['avatar_upload_nonce'] ) || ! wp_verify_nonce( $_POST['avatar_upload_nonce'], 'upload_avatar_action' ) ) {
wp_die( esc_html__( 'Ugyldig sikkerhetstoken.', 'secure-plugin' ) );
}
// 2. Verifiser capability-sjekker
if ( ! current_user_can( 'upload_files' ) ) {
wp_die( esc_html__( 'Du har ikke rettighet til å laste opp filer.', 'secure-plugin' ) );
}
if ( isset( $_FILES['avatar'] ) ) {
if ( ! function_exists( 'wp_handle_upload' ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
// 3. Tving begrensning av tillatte MIME-typer
$allowed_mimes = [
'jpg|jpeg' => 'image/jpeg',
'png' => 'image/png'
];
$upload_overrides = [
'test_form' => false,
'mimes' => $allowed_mimes
];
// 4. Deleger opplastingsbehandling til kjernefunksjonen
$movefile = wp_handle_upload( $_FILES['avatar'], $upload_overrides );
if ( $movefile && ! isset( $movefile['error'] ) ) {
$avatar_url = $movefile['url'];
update_user_meta( get_current_user_id(), 'user_avatar', $avatar_url );
} else {
// Logg feilen sikkert
error_log( 'Filopplasting feilet: ' . $movefile['error'] );
}
}
}
6. Hallusinerte API-er og uverifisert opphav for avhengigheter
En feiltype som er unik for generative modeller, er den selvsikre oppfinnelsen av kode som ikke finnes. Fordi en språkmodell forutser sannsynlige token i stedet for å slå opp i den faktiske WordPress-referansen, kaller den gjerne på funksjoner som aldri har vært en del av kjernen, som wp_verify_admin(), get_current_user_role() eller sanitize_all_input(). Navnene virker ekte fordi de følger WordPress’ navnekonvensjoner, og en fatal feil under kjøring er ofte det første tegnet på at noe er galt. Enda verre: en utvikler med dårlig tid “retter” den fatale feilen ved å skrive sin egen tynne innpakning rundt det hallusinerte navnet, og gjeninnfører dermed nøyaktig det hullet i sanitysering eller rettighetskontroll som den oppdiktede funksjonen lot som den lukket. AI kan på samme måte finne opp action- og filter-kroker som aldri utløses, slik at valideringskoden knyttet til dem blir død og gir en falsk følelse av trygghet.
Det samme mønsteret gjelder tredjeparts-avhengigheter. Når KI-en setter opp en composer.json eller foreslår require-linjer, kan den vise til pakker som ikke finnes på Packagist, eller enda farligere, til pakker med et navn som skiller seg fra et ekte bibliotek med bare ett tegn. Angripere utnytter denne “slopsquatting”-oppførselen ved å registrere de hallusinerte pakkenavnene på forhånd, slik at en uverifisert composer install trekker skadelig kode rett inn i pluginet.
To konkrete kontroller lukker dette gapet. For det første: sammenlign hver ukjente funksjon med den offisielle WordPress-kodereferansen på developer.wordpress.org før du stoler på den; finnes det ingen oppføring, behandle kallet som oppdiktet. For det andre: lås og gjennomgå hver avhengighet, bekreft at pakken finnes akkurat slik, kommer fra vedlikeholderen du forventer, og er låst til en gjennomgått versjon i stedet for et flytende versjonskrav.
// Hallusinert: en slik kjernefunksjon finnes ikke
if ( wp_current_user_is_admin() ) { /* ... */ }
// Ekte WordPress-API
if ( current_user_can( 'manage_options' ) ) { /* ... */ }
Kjør composer why og wp plugin verify-checksums på hver genererte pakke for å bekrefte at ingenting er byttet ut i det stille før koden når testmiljøet.
Revisjonsmetodikk: Implementering av Zero Trust for AI-kode
For å distribuere AI-generert kode på en sikker måte, må ingeniørteamet ditt etablere en systematisk gjennomgangsprosess. Implementer disse tre trinnene før du skyver genererte ressurser til produksjon:
Trinn 1: Automatiser statisk analyse (PHPCS)
Konfigurer WordPress Coding Standards (WPCS) for PHP_CodeSniffer-verktøyet. Det skanner filer og flagger manglende sanitysering, utelatte nonces og uescapede variabler automatisk.
# Skann en generert plugin-fil med WordPress-standarder
vendor/bin/phpcs --standard=WordPress-Extra path/to/generated-plugin.php
Trinn 2: Gjennomfør en manuell kodegjennomgang
Gjennomgå hver handler som utfører HTTP-spørringer, databasetransaksjoner, AJAX-anrop eller REST API-tilkoblinger mot følgende flytskjema:
graph TD
A["Motta AI-skrevet plugin-kode"] --> B{"Godtar den brukerinput?"}
B -- Ja --> C["Sjekk for Nonce og Capability-sjekker"]
B -- Nei --> D{"Modifiserer den databasen?"}
C --> C1["Implementer check_ajax_referer() / CSRF-validering"]
C --> C2["Implementer current_user_can() rettighetssjekk"]
C1 --> D
C2 --> D
D -- Yes --> E["Sjekk for $wpdb->prepare() bruk"]
D -- No --> F{"Sender den utdata til nettleseren?"}
E --> E1["Implementer parametriserte SQL-variabler"]
E1 --> F
F -- Yes --> G["Verifiser esc_html(), esc_attr(), eller esc_url()"]
F -- No --> H["Fortsett til integrasjonstesting"]
G --> G1["Implementer kontekstuell utdata-escaping"]
G1 --> H
Trinn 3: Kjør tester med lave rettigheter
Verifiser kodens adgangsgrenser. Logg inn som en bruker med rollen “Abonnent” og utløs pluginens REST- eller AJAX-handlinger direkte via curl eller Postman. Hvis serveren utfører modifikasjoner eller avslører databasedata, mangler rettighetslagene.
Sammendrag og anbefalinger
Kunstig intelligens er en kraftig akselerator for å skrive kode, men den kan ikke overta ingeniøransvar. Behandle all AI-skrevet kode som om den var skrevet av en uerfaren praktikant.
Sørg for at du implementerer robuste capability-sjekker (current_user_can()), CSRF-verifisering (wp_verify_nonce()), databaseparametrisering ($wpdb->prepare()), sanitysering av inndata og sen escaping av utdata. Ved å kombinere disse kjernepraksisene med statiske analyseverktøy, kan du skrive WordPress-kode raskere samtidig som du opprettholder en helt sikker applikasjon.







