Data Sanitization og validering med WordPress

Riktig sikkerhet er avgjørende for å holde nettstedet ditt eller det som er tema eller plugin-brukere trygt. En del av det betyr passende data validering og sanitisering. I denne artikkelen skal vi se på hvorfor dette er viktig, hva som må gjøres, og hvilke funksjoner WordPress gir for å hjelpe.

Siden det synes å være forskjellige tolkninger av hva begreperne 'validering', 'rømming' og 'sanitisering' betyr, vil jeg først avklare hva jeg mener med dem i denne artikkelen:

  • Validering - Dette er kontrollene som kjøres for å sikre dataene du ha er det det bør være. For eksempel ser en e-post ut som en e-postadresse, at en dato er en dato, og at et tall er (eller er kastet som) et heltall
  • Sanitisering / unnslippe - Dette er filtre som brukes på data for å gjøre det "trygt" i en bestemt sammenheng. For eksempel, for å vise HTML-kode i et tekstområde, ville det være nødvendig å erstatte alle HTML-kodene ved deres enhetskvivalenter

Hvorfor er sanering viktig?

Når data er inkludert i en kontekst (si i et HTML-dokument) - kan dataene misforstås som en kode for det aktuelle miljøet (for eksempel HTML-kode). Hvis disse dataene inneholder skadelig kode, betyr det at koden vil bli utført, da du bruker dataene uten å sanere det. Koden trenger ikke engang å være skadelig for at den vil forårsake uønskede effekter. Arbeidet med sanitisering er å sørge for at enhver kode i dataene ikke tolkes som kode - ellers kan du ende opp som Bobby Tables 'skole ...

'Utnyttelse av et mamma' - xkcd

Et tilsynelatende uskyldig eksempel kan være å fylle ut et søkefelt med det aktuelle spørsmålet, ved hjelp av det ubestemte $ _GET [ 's']:

 

Dette åpner et sikkerhetsproblem som kan tillate at javascript injiseres ved å for eksempel lure noen til å besøke http://yoursite.com?s= "/>. Søketermen "hopper" ut av verdien attributtet, og følgende del av dataene tolkes som kode og kjøres. For å forhindre dette, gir WordPress get_search_query som returnerer det sanitiserte søket. Selv om dette er et "ufarlig" eksempel, kan det injiserte skriptet være langt mer ondsinnet, og i beste fall vil det bare "bryte" skjemaet hvis søkeord inneholder dobbelte sitater.

Hvordan denne ondsinnede (eller andre) koden kan ha funnet sin vei på nettstedet ditt, er ikke bekymringen her - men heller er det å hindre det fra å utføre. Vi legger heller ikke grunnlag for antagelser om arten av denne uønskede koden eller dens hensikt - det kunne ganske enkelt vært en feil på brukerens side. Dette bringer meg til å styre No.1 ...


Regel nr. 1: Stol på ingen

Det er en vanlig maksimal som brukes med hensyn til data sanitisering, og det er en god en. Tanken er at du ikke bør anta at data som er oppgitt av brukeren, er trygt. Du må heller ikke anta at dataene du har hentet fra databasen, er trygge - selv om du hadde gjort det trygt før du setter det inn der. Faktisk, om data kan betraktes som "trygt", gir ingen mening uten kontekst. Noen ganger kan de samme dataene brukes i flere sammenhenger på samme side. Titler kan for eksempel sikkert inneholde sitater eller dobbelte anførselstegn når de er inne i topptekstene - men vil føre til problemer hvis de brukes (unescaped) inne i et tittelattributt for en linketikett. Så det er ganske meningsløst å gjøre data "trygge" når de legges til databasen, siden det ofte er umulig å lage data trygt for alle sammenhenger samtidig. (Selvfølgelig må det gjøres trygt å legge til i databasen - men vi kommer til det senere).

Selv om du bare har tenkt å bruke dataene i en bestemt kontekst, si et skjema, er det fortsatt meningsløst å sanitisere dataene når du skriver til databasen, fordi du ikke kan stole på at det fortsatt er trygt når du ta det ut igjen.


Regel nr. 2: Bekreft på Input, Escape on Output

Dette er prosessmåten som angir når du skal validere data, og når du sanitiserer det. Enkelt sagt - bekreft dine data (sjekk det er hva det skal være - og at det er "gyldig") så snart du mottar det fra brukeren. Når du kommer til å bruke disse dataene, for eksempel når du skriver det ut, må du unnslippe (eller desinfisere) det. Hvilken form denne sanitiseringen tar, avhenger helt av konteksten du bruker den i.

Det beste rådet er å utføre dette "sent": Unngå dataene dine umiddelbart før du bruker eller viser det. På denne måten kan du være sikker på at dataene dine er riktig sanitert, og du trenger ikke å huske om dataene tidligere er sjekket.


Regel nr. 3: Stol på WordPress

Du kan tenke "Ok, validere før du skriver til database og sanitize når du bruker den. Men trenger jeg ikke å sørge for at dataene er trygge å skrive til databasen?". Generelt, ja. Når du legger til data i en database, eller bare bruker et inngang for å samhandle med en database, må du unnslippe dataene hvis det inneholdt noen SQL-kommandoer. Men dette bringer meg til Regel nr. 3, en som flyr i møte med Regel nr. 1: Stol på WordPress.

I en tidligere artikkel tok jeg brukerinngang (sendt fra et søkeskjema via AJAX) og brukte det direkte med get_posts () å returnere innlegg som matchet dette søket:

 $ posts = get_posts (array ('s' => $ _ REQUEST ['term']));

En observant leser la merke til at jeg ikke hadde gjort noen sanitisering - og de hadde rett. Men jeg trengte ikke. Når du bruker høyt nivå funksjoner som get_posts (), du trenger ikke å bekymre deg for å sanitere dataene - fordi databasespørsmålene er alle skikkelig rømt av WordPress 'internals. Det er en annen sak helt hvis du bruker en direkte SQL-spørring - men vi vil se på dette i en senere seksjon. Tilsvarende fungerer som tittelen(), the_permalink (), innholdet() etc. utføre sin egen sanitisering (for riktig kontekst).


Datavalidering

Når du mottar data som er oppgitt av en bruker, er det viktig å validere den. (Innstillings-API, dekket i denne serien, lar deg spesifisere en tilbakeringingsfunksjon for å gjøre akkurat dette). Ugyldige data blir enten automatisk korrigert, eller prosessen avbrytes og brukeren returneres til skjemaet for å prøve igjen (forhåpentligvis med en passende feilmelding). Bekymringen her er ikke sikkerhet, men heller gyldighet - hvis du gjør det riktig, vil WordPress ta vare på å legge til dataene i databasen. Hva "gyldig" betyr er opp til deg - det kan bety en gyldig e-postadresse, et positivt heltall, en tekst med begrenset lengde eller en av en rekke angitte alternativer. Men du tar sikte på å bestemme gyldigheten, WordPress tilbyr mange funksjoner som kan hjelpe.

tall

Når du forventer numeriske data, er det mulig å sjekke om dataene "er noen form for nummer", for eksempel is_int eller is_float. Vanligvis er det tilstrekkelig å bare kaste dataene som numeriske med: intval eller floatval.

Hvis du trenger å sikre at nummeret er polstret med ledende nuller, gir WordPress funksjonen zeroise (). Som tar følgende parametere:

  • Nummer - tallet til pute
  • Terskel - Antall siffer nummeret vil bli polstret til

For eksempel:

 ekko nullise (70,4); // Skriver 0070

E-post

For å sjekke gyldigheten av e-post, har WordPress den is_email () funksjon. Denne funksjonen bruker enkle kontroller for å validere adressen. For eksempel kontrollerer den at den inneholder '@' -symbolet, at det er lengre enn 3 tegn, domenet inneholder bare alfanumeriske og bindestreker og så videre. Tydeligvis kontrollerer den ikke at e-postadressen faktisk eksisterer. Forutsatt at e-postadressen passerte kontrollene, returneres den, ellers returneres "false".

 $ email = is_email (isomeone@e ^ sample.com '); // $ email er satt til false. $ email = is_email ([email protected] '); // $ email er satt til '[email protected]'.

HTML

Ofte kan du bare tillate det noen HTML-koder i dataene dine - for eksempel i kommentarer som er lagt ut på nettstedet ditt. WordPress gir en familie av funksjoner i skjemaet wp_kses_ * (KSES Strips Evil Scripts). Disse funksjonene fjerner (noen delmengde av) HTML-koder, og kan brukes til å sikre at koblinger i dataene er av angitte protokoller. For eksempel wp_kses () funksjonen godtar tre argumenter:

  • innhold - (streng) Innhold for å filtrere gjennom kses
  • allowed_html - Et array hvor hver nøkkel er et tillatt HTML-element, og verdien er en rekke tillatte attributter for det elementet
  • allowed_protocols - Valgfri. Tillatt protokoll i koblinger (for eksempel http, mailto, mate etc.)

wp_kses () er en veldig fleksibel funksjon, slik at du kan fjerne uønskede koder eller bare uønskede attributter fra koder. For eksempel, for å bare tillate eller koder (men bare tillat href-attributtet):

 $ content = "Klikk her for å besøke  wptuts+ "; echo wp_kses ($ content, array ('strong' => array (), 'a' => array ('href')); // Skriver HTML  wptuts+ ": Klikk her for å besøke  wptuts+ 

Selvfølgelig kan spesifisering av hver tillatt tag og hvert tillatt attributt være en mektig oppgave. Så WordPress gir andre funksjoner som lar deg bruke wp_kses med forhåndsdefinerte tillatte merker og protokoller - nemlig de som brukes til å validere innlegg og kommentarer:

  • wp_kses_post ()
  • wp_kses_data ()

Ovennevnte funksjoner er nyttige for å sikre at HTML mottatt fra brukeren bare inneholder hviteliste elementer. Når vi har gjort det, vil vi også gjerne sørge for at hver tag er balansert, det vil si at hver åpningskode har tilhørende lukkekode. For dette kan vi bruke balanceTags (). Denne funksjonen godtar to argumenter:

  • innhold - Innhold for å filtrere og balansere koder for
  • kraftbalanse - Sann eller falsk, om du skal tvinge balanseringen av koder
 // Innhold med manglende lukking  tag $ content = "Klikk her for å besøke  wptuts + "; ekkobalanseTags ($ innhold, sant), // Skriver HTML-koden" Klikk her for å besøke  wptuts+ "

filnavn

Hvis du vil opprette en fil i en av nettstedets kataloger, vil du være sikker på at filnavnet er både gyldig og lovlig. Du vil også forsikre deg om at filnavnet er unikt for den katalogen. For denne WordPress gir:

  • sanitize_file_name ($ filnavn) - sanitiserer (eller validerer) filnavnet ved å fjerne tegn som er ulovlige i filnavn på visse operativsystemer, eller det vil kreve at man flyr på kommandolinjen. Erstatter mellomrom med bindestreker og sammenhengende bindestreker med en enkelt dash og fjerner perioder, bindestreker og understreker fra begynnelsen og slutten av filnavnet.
  • wp_unique_filename ($ dir, $ filnavn) - returnerer en unik (for katalog $ dir), sanitized filnavn (det bruker sanitize_file_name).

Data fra tekstfelt

Når du mottar data innført i et tekstfelt, vil du sannsynligvis stripe ut ekstra hvite mellomrom, faner og linjeskift, samt fjerne eventuelle tagger. For dette WordPress gir sanitize_text_field ().

Keys

WordPress gir også sanitize_key. Dette er en veldig generisk (og noen ganger nyttig) funksjon. Det sikrer at den returnerte variabelen bare inneholder bare små bokstaver, bindestreker og understreker.


Data Sanitization

Mens validering er opptatt av å sikre at data er gyldig - data sanitisering handler om å gjøre det sikker. Selv om noen av valideringsfunksjonene som er omtalt ovenfor, kan være nyttige for å sikre at dataene er trygge - det er generelt ikke tilstrekkelig. Selv "gyldige" data kan være usikre i visse sammenhenger.


Regel nr. 4: Gjøre data trygt handler om sammenheng

Bare si at du ikke kan spørre "Hvordan lagrer jeg disse dataene?". I stedet bør du spørre, "Hvordan lager jeg disse dataene for å bruke det i X".

For å illustrere dette punktet, anta at du har en widget med en textarea hvor du har til hensikt å la brukeren legge inn noen HTML. Anta at de da angir:

  Hei Verden

Dette er helt gyldig og trygt, HTML - men når du klikker lagre, finner vi at teksten har hoppet ut av tekstområdet. HTML-koden er ikke sikker som en verdi for tekstområdet:

Det som er trygt å bruke i en kontekst, er ikke nødvendigvis trygt i en annen. Når du bruker eller viser data, må du huske hvilke former for sanitisering som må gjøres for å gjøre bruk av dataene trygge. Dette er grunnen til at WordPress ofte gir flere funksjoner for det samme innholdet, for eksempel:

Alle utfører den nødvendige sanitering for en bestemt kontekst - og hvis du bruker dem, bør du være sikker på å bruke den riktige. Noen ganger skjønner vi imidlertid at vi skal utføre vår egen sanitering - ofte fordi vi har tilpasset innføring utover standard posttittel, permalink, innhold etc. som WordPress håndterer for oss.

Unnslippe HTML

Når du skriver ut variabler til siden, må vi være oppmerksom på hvordan nettleseren vil tolke dem. La oss vurdere følgende eksempel:

 

Anta $ title = . Snarere enn å vise HTML-koden

Faktisk, hvis du gjør dette, bør du nesten sikkert bruke wp_localize_script () - som håndterer sanitisering for deg. (Hvis noen kan tenke på en grunn hvorfor du kanskje må bruke den ovennevnte metoden i stedet, vil jeg gjerne høre det).

For å gjøre eksemplet ovenfor trygt kan du bruke esc_js funksjon:

 

Unnslippe Textarea

Når du viser innhold i en tekstområde, esc_html er ikke tilstrekkelig fordi det Dobbeltkod ikke enheter. For eksempel:

 tekst modig'?> 

$ var trykt i tekstområdet vil vises som:

 tekst modig

Snarere enn å også kode for & som & i tags.

For dette WordPress gir esc_textarea, som er nesten identisk med esc_html, men dobbeltkodes enheter. I hovedsak er det lite mer enn en wrapper for htmlspecialchars. I dette eksemplet:

 tekst modig'?> 

Antispambot

Viser e-postadresser på nettstedet ditt gjør dem utsatt for e-postopptakere. En enkel metode er å skjule e-postadressen. WordPress gir antispambot, som koder for tilfeldige deler av e-postadressen i deres HTML-enheter (og heksadesimale ekvivalenter hvis $ mailto = 1). På hver side belastes kodingen skal være annerledes, og mens den returnerte adressen gjøres riktig i nettleseren, skal den vises som gobbledygook til spambots. Funksjonen godtar to argumenter:

  • e-post - adressen til obfuscate
  • mailto - 1 eller 0 (1 hvis du bruker mailto-protokollen i en lenke)
 $ email = "[email protected]"; $ email = sanitize_email ($ email); ekko '' .antispambot ($ email). ' ';

Query Strings

Hvis du vil legge til (eller fjerne) variabler fra en spørringsstreng (dette er veldig nyttig hvis du vil tillate brukere å velge en bestilling for innleggene dine), er den sikreste og enkleste måten å bruke add_query_arg og remove_query_arg. Disse funksjonene håndterer all nødvendig rømning for for argumentene og deres verdier for bruk i nettadressen.

add_query_arg aksepterer to argumenter:

  • spørringsparametere - et assosiativt utvalg av parametere -> verdier
  • url - URL til å legge til parametrene og deres verdier til. Hvis utelatt, brukes nettadressen til gjeldende side

remove_query_arg aksepterer også to argumenter, den første er en rekke parametere for å fjerne, den andre er som ovenfor.

 // Hvis vi er på www.example.com/wp-admin/edit.php?post_type=book $ query_params = array ('page' => 'my-bage'); $ url = add_query_arg ($ query_params); // Ville sette $ url til: // www.example.com/wp-admin/edit.php?post_type=book&page=mypage

Validering og sanering

Som tidligere nevnt, gjør sanitisering ikke mye mening uten en kontekst - så det er ganske meningsløst å sanitisere data når du skriver til databasen. Ofte må du lagre data i råformatet uansett, og i hvert fall - Regel nr. 1 dikterer at vi alltid skal sanitere på produksjonen.

Validering av data, derimot, skal gjøres så snart den er mottatt og før den er skrevet til databasen. Tanken er at "ugyldige" data enten skal bli automatisk korrigert eller flagget til dataene, og bare gyldige data skal gis til databasen.

Når det er sagt, kan du også utføre validering når data vises også. Faktisk noen ganger vil "validering" også sikre at dataene er trygge. Men prioriteten her er på sikkerhet, og du bør unngå overdreven validering som kjører på hver side last (den wp_kses_ * funksjoner, for eksempel, er svært dyre å utføre).


Database unnslippe

Når du bruker funksjoner som get_posts eller klasser som WP_Query og WP_User_Query, WordPress tar seg av den nødvendige sanitering ved å spørre databasen. Men når du henter data fra et tilpasset bord, eller på annen måte utfører en direkte SQL-spørring på databasen - er riktig sanitisering da opp til deg. WordPress gir imidlertid en nyttig klasse, den $ wpdb klasse, som hjelper med å rømme SQL-spørringer.

La oss vurdere denne grunnleggende 'Å VELGE'kommando, hvor $ alder og $ firstname er variabler som lagrer en alder og et navn som vi spør:

 VELGE * WHERE alder = "$ alder" OG fornavn = '$ fornavn'

Vi har ikke rømt disse variablene, slik at potensielle kommandoer kan injiseres i. Låner xkcds eksempel ovenfra:

 $ alder = 14; $ firstname = "Robert"; DROP TABLE Students; "; $ sql = "SELECT * WHERE alder =" $ alder "OG firstname = '$ firstname';"; $ results = $ wpdb-> spørring

Vil kjøres som kommando (r):

 SELECT * WHERE alder = "14" OG fornavn = 'Robert'; DROP TABLE Studenter; ';

Og slett hele studentbordet vårt.

For å forhindre dette kan vi bruke $ Wpdb-> forberede metode. Dette aksepterer to parametere:

  • SQL-kommandoen som en streng, hvor strengvariabler erstattes av stedholderen % s og desimaltall erstattes av plassholderen % d og flyter av % f
  • En rekke verdier for de ovennevnte plassholderne, i den rekkefølgen de vises i spørringen

I dette eksemplet:

 $ alder = 14; $ firstname = "Robert"; DROP TABLE Students; "; $ sql = $ wpdb-> klargjør ('VELG * WHERE alder =% d OG firstname =% s;', array ($ alder, $ fornavn)); $ results = $ wpdb-> get_results ($ sql);

Den rømte SQL-spørringen ($ sql i dette eksempelet) kan da brukes med en av metodene:

  • $ Wpdb-> get_row ($ sql)
  • $ Wpdb-> get_var ($ sql)
  • $ Wpdb-> get_results ($ sql)
  • $ Wpdb-> get_col ($ sql)
  • $ Wpdb-> spørring ($ sql)

Sette inn og oppdatere data

For å sette inn eller oppdatere data, gjør WordPress livet enda enklere ved å tilby $ Wpdb-> Sett () og $ Wpdb-> oppdateringen () fremgangsmåter.

De $ Wpdb-> Sett () Metoden aksepterer tre argumenter:

  • Tabellnavn - navnet på bordet
  • Data - rekke data som skal settes inn som kolonne-> verdipar
  • formater - rekke formater for de tilsvarende verdiene ('% s''% d'eller'% f')
 $ alder = 14; $ firstname = "Robert"; DROP TABLE Students; "; $ wpdb-> insert ('Student', array ('firstname' => $ firstname, 'age' => $ alder), array ('% s', '% d'));

De $ Wpdb-> oppdateringen () Metoden godtar fem argumenter:

  • Tabellnavn - navnet på bordet
  • Data - rekke data som skal oppdateres som kolonne-> verdipar
  • Hvor - rekke data som skal matche som kolonne-> verdipar
  • Dataformat - rekke formater for de tilsvarende dataværdiene
  • Hvor Format - rekke formater for de tilsvarende "hvor" -verdiene
 // Oppdater Robert '; DROP TABLE Studenter; til Bobby $ oldname = "Robert"; DROP TABLE Students; "; $ newname = "bobby"; $ wpdb-> update ('Student', array ('firstname' => $ nynavn), array ('firstname' => $ fornavn), array ('% s'), array ('% s'));

Begge $ Wpdb-> Sett () og $ Wpdb-> oppdateringen () metoder utfører all nødvendig sanitisering for å skrive til databasen.

Som uttalelser

Fordi det $ Wpdb-> forberede metoden bruker % For å skille mellom innehaverne, må det tas vare på når du bruker % wildcard i SQL LIKE-setninger. Codex antyder å rømme dem med et sekund %. Alternativt kan du unnslippe begrepet som skal søkes etter med like_escape og legg deretter til jokertegnet % når det er hensiktsmessig, før du inkludere dette i spørringen ved hjelp av forberedelsesmetoden. For eksempel:

 $ Alder = 14; $ firstname = "Robert"; DROP TABLE Students; "; SELECT * WHERE alder = $ alder (fornavn som '% $ firstname%');

Ville bli gjort trygg med:

 $ Alder = 14; $ firstname = "Robert"; DROP TABLE Students; "; SELECT * WHERE alder = $ alder OG (fornavn som '% $ firstname%'); $ query = $ wpdb-> utarbeide ('VELG * WHERE alder =% d OG (fornavn LIKE% s);', array ($ alder, '%'. like_escape ($ firstname). '%'));

Sammendrag

Dette er ikke en uttømmende liste over funksjonene som er tilgjengelige for validering og sanitisering, men det bør dekke det store flertallet av brukstilfeller. Mange av disse (og andre) funksjonene finnes i /wp-includes/formatting.php og jeg anbefaler på det sterkeste å grave inn i kjernekoden og se på hvordan WordPress-kjerne gjør validering og sanitisering av data.

Fant du denne artikkelen nyttig? Har du ytterligere forslag til beste praksis for datavalidering og sanitisering i WordPress? Gi oss beskjed i kommentarene nedenfor.