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:
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 ...
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.
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.
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).
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.
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:
For eksempel:
ekko nullise (70,4); // Skriver 0070
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]'.
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 ksesallowed_html
- Et array hvor hver nøkkel er et tillatt HTML-element, og verdien er en rekke tillatte attributter for det elementetallowed_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 med manglende lukking tag $ content = "Klikk her for å besøke wptuts + "; ekkobalanseTags ($ innhold, sant), // Skriver HTML-koden" Klikk her for å besøke wptuts+ "
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
).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 ()
.
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.
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.
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:
tittelen
- for å bruke tittelen i standard HTML (for eksempel header koder, for eksempel)the_title_attribute
- for å bruke tittelen som en attributtverdi (vanligvis tittelattributtet i
tags)the_title_rss
- for å bruke tittelen i RSS-feederAlle 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.
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 tags, they will be interpreted as HTML and the enclosed javascript would be injected into the page.
This form of injection (as also demonstrated in the search form example) is called Cross-site scripting and this benign example belies its severity. Injected script can essentially control the browser and 'act on behalf' of the user or steal the user's cookies. This becomes an even more serious issue if the user is logged in. To prevent variables printed inside HTML being interpreted as HTML, WordPress provides the well known esc_html
function. In this example:
Now consider the following example:
Because $value
contains double quotes, unescaped it can jump out of the value attribute and inject script, for example, by using the onfocus
attribute. To escape unsafe characters (such as quotes, and double-quotes in this case), WordPress provides the function esc_attr
. Like esc_html
it replaces 'unsafe' characters by their entity equivalents. In fact, at the time of writing, these functions are identical - but you should still use the one that is appropriate for the context.
For this example we should have:
Both esc_html
and esc_attr
also come with __
, _e
, and _x
variants.
esc_html__('Text to translate', 'plugin-domain')
/ esc_attr__
- returns the escaped translated text,esc_html_e('Text to translate', 'plugin-domain')
/ esc_attr_e
- displays the escaped translated text and finally theesc_html_x('Text to translate', $context, 'plugin-domain')
/ esc_attr_x
- translates the text according to the passed context, and then returns the escaped translationFor class names, WordPress provides sanitize_html_class
- this escapes variables for use in class names, simply by restricting the returned value to alpha-numerics, hyphens and underscores. Note: It does not ensure the class name is valid (reference: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier).
In CSS, identifiers can contain only the characters
[a-zA-Z0-9]
and ISO 10646 characters U+00A0 and higher, plus the hyphen (-
) and the underscore (_
); they cannot start with a digit, two hyphens, or a hyphen followed by a digit. Identifiers can also contain escaped characters and any ISO 10646 character as a numeric code.
Let's now look at another common practise, printing variables into the href
attribute:
" title="Link Title"> Link Text
Clearly it is vulnerable to the same form of attack as illustrated in escaping HTML and attributes. But what if the $url
was set as follows:
$url = 'javascript:alert(\'Injected javascript\')'
On clicking the link, the alert function would be fired. This contains no HTML, or any quotes that allow it to jump out of the href attribute - so esc_attr
is not sufficient here. This is why context matters: esc_attr($url)
would be safe in the title
attribute, but not for the href
attribute - and this is because of the javascript protocol - which while perfectly valid - is not to be considered safe in this context. Instead you should use:
esc_url
- for escaping URLs that will be printed to the page.esc_url_raw
- for escaping URLs to save to the database or use in URL redirecting.esc_url
strips out various offending characters, and replaces quotes and ampersands with their entity equivalents. It then checks that the protocol being used is allowed (javascript, by default, isn't).
What esc_url_raw
does is almost identical to esc_url
, but it does not replace ampersands and single quotes (which you don't want to, when using the URL as an URL, rather than displaying it).
In this example, we are displaying the URL, so we use esc_url:
" title="Link Title"> Link Text
Although not necessary in most cases, both functions accept an optional array to specify which protocols (such as http
, https
, ftp
, ftps
, mailto
, etc) you wish to allow.
Sometimes you'll want to print javascript variables to a page (usually in the head):
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:
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'?>
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 obfuscatemailto
- 1 eller 0 (1 hvis du bruker mailto-protokollen i en lenke)$ email = "[email protected]"; $ email = sanitize_email ($ email); ekko '' .antispambot ($ email). ' ';
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 -> verdierurl
- URL til å legge til parametrene og deres verdier til. Hvis utelatt, brukes nettadressen til gjeldende sideremove_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
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).
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:
% s
og desimaltall erstattes av plassholderen % d
og flyter av % f
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)
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:
% 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:
// 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.
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). '%'));
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.