De două ori pe lună, revizuim câteva postări preferate ale cititorilor noștri de-a lungul istoriei Nettuts +. Acest tutorial a fost publicat pentru prima oară în iulie 2008.
Versiunea 1 merge aur! Vizitatorii aterizează din orice colț al globului. Știți că este posibil să fie câteva probleme de dentiție; Vreau să spun, asta e 1.0.0.0? toate aceste zerouri sunt menite să ne permită un mic har, bine?
Poate că acea foaie de stil nu va fi cascadă elegant pe browser-ul X. Un comentariu incomplet scapă o marjă ruptă. Poate ar fi trebuit să fi persistat acele conexiuni de baze de date la urma urmei. Hei, cu toții ne uităm lucrurile în entuziasmul de a face prima noastră versiune să fie difuzată - dar câte dintre aceste depășiri ne putem bucura de stomac fericit și câte ar putea lăsa un gust amar la a noastră, și mai dureros gura clientului nostru?
Acest articol trece prin faza de brainstorming a planificării pentru ceea ce este, în acest caz, o aplicație web ipotetică orientată spre utilizator.
Deși nu veți rămâne cu un proiect complet și nici cu un cadru pregătit pentru piață, sperăm că fiecare dintre voi, atunci când vă confruntați cu sarcini de lucru viitoare, ar putea să vă mute cu privire la cele mai bune practici descrise. Deci, fără să mai vorbim? Stați confortabil?
Am fost rugați de către clientul nostru să includă într-un site existent, un sistem de recenzare a cărților. Site-ul are deja conturi de utilizator și permite un comentariu anonim.
După o discuție rapidă cu clientul, avem următoarele specificații pentru implementare și numai douăzeci și patru de ore pentru a face acest lucru:
Notă: serverul clientului rulează PHP5 și MySQL - dar aceste detalii nu sunt critice pentru a înțelege bugbear-urile prezentate în acest articol.
Clientul nostru ne-a oferit a PHP include pentru a avea acces la baza de date:
De fapt, nu avem nevoie de sursa acestui fișier pentru ao folosi. De fapt, dacă clientul ne-a spus doar unde a trăit, am putea să îl folosim cu o declarație de includere și cu $ db
variabil.
Până la autorizare? în cadrul schemei datate, suntem preocupați de următoarele nume de coloane:
Dat fiind faptul că lucrăm împotriva ceasului? să scriem o funcție PHP cât de repede putem folosi noi pentru a ne autentifica utilizatorii:
În codul de mai sus veți observa că am evidențiat o zonă de chihlimbar și o zonă roșie.
De ce am subliniat nu atât de periculos $ _REQUEST
variabile?
Deși acest lucru nu expune nici un pericol real, ceea ce permite acest lucru este o abordare laxă atunci când vine vorba de codul de partea clientului. PHP are trei matrice pe care majoritatea dintre noi le folosesc pentru a obține datele noastre trimise de la utilizatori și, de cele mai multe ori, am putea fi tentați să folosim $ _REQUEST.
Această matrice oferă în mod convenabil accesul nostru PHP la variabilele POST și GET, dar aici există o posibilitate de suspendare?
Luați în considerare următorul scenariu. V-ați scris clientul dvs. de cod pentru a utiliza POST solicitări, dar predați proiectul în timp ce luați o pauză - și când vă întoarceți, adversarul dvs. a scris câteva cerințe GET în proiect. Totul merge bine - dar nu ar trebui.
Puțin mai târziu, un utilizator care nu se întreabă scrie o legătură externă într-o casetă de comentarii și, înainte de a ști, site-ul extern are o combinație de nume de utilizator / parolă în jurnalele sale de referințe.
Referindu - se la $ _POST
variabile în loc de $ _REQUEST
, eliminăm accidental publicând orice cod de lucru care ar putea dezvălui o solicitare GET riscantă.
Același principiu se aplică și identificatorilor de sesiuni. Dacă găsiți că scrieți variabile de sesiune în adrese URL, fie că faceți ceva greșit, fie că aveți ceva foarte bine motiv pentru a face acest lucru.
Referindu-se din nou la codul PHP, linia roșie evidențiată s-ar fi putut sări de la unii dintre voi? Pentru cei care nu au constatat problema, vă voi da un exemplu și de acolo, dacă vă dau ceva riscant.
Cea mai rapidă protecție este de a dezbrăca împrejmuire caractere sau să le scape.
Această imagine clarifică defectele în inserarea variabilelor direct în instrucțiunile SQL. Deși nu se poate spune exact ce
de control un utilizator rău intenționat ar putea avea - este garantat, dacă utilizați această metodă pentru a strânge împreună o instrucțiune SQL, că serverul dvs. este abia protejat. Exemplul de mai sus este destul de periculos pe un cont numai pentru citire; puterile pe care le are o conexiune de citire / scriere sunt limitate doar de imaginația ta.
Protecția împotriva injecției SQL este de fapt destul de ușoară. Să aruncăm o privire în primul rând asupra cazului de variație a șirului de cotate închise:
Cea mai rapidă soluție este de a elimina împrejmuire caractere sau să le scape. Din PHP 4.3.0, funcția mysql_real_escape_string
a fost disponibil pentru a curăța șiruri de intrare. Funcția ia șirul brut ca un singur parametru și returnează șirul cu caracterele volatile scăpate. in orice caz mysql_real_escape_string
nu scapă toate caracterele care sunt caractere de control valide în SQL? elementele evidențiate în imaginea de mai jos arată tehnicile pe care le folosesc pentru dezintoxicare String, Număr și boolean valorile.
Primul punct culminant, linia care stabilește $ string_b
utilizează o funcție PHP numită addcslashes
. Această funcție a făcut parte din PHP de la versiunea 4 și, așa cum este scris în exemplul de mai sus, este metoda mea preferată pentru sănătatea și securitatea șirului SQL.
O multitudine de informații sunt disponibile în documentația PHP, dar voi explica pe scurt ce addcslashes
și cum diferă de la ea mysql_real_escape_string
.
Din diagrama de mai sus puteți vedea asta mysql_real_escape_string
nu adaugă pietre la caracterul (%) la sută.
%
este folosit în SQL CA
clauze, precum și câteva altele. Se comportă ca un wildcard și nu un caracter literal. Deci, ar trebui să fie scăpat de un caracter retrospectiv precedent în orice caz în care literalul de șir formează o instrucțiune SQL.
Al doilea parametru, trec la addcslashes
, care este în imagine îndrăzneţ; este grupul de caractere PHP care va adăuga pietre pentru. În cele mai multe cazuri, va fi Despică șirul pe care îl oferiți caractere, și apoi să opereze pe fiecare. Este demn de remarcat faptul că acest grup de caractere poate fi, de asemenea, alimentat cu o serie de caractere, deși acest lucru depășește domeniul de aplicare al acestui articol. În scenariile pe care le discutăm, putem folosi caractere alfanumerice literal, de ex. ? Abcd1234? și toate celelalte caractere, fie ca literal în stilul lor C? \ r \ n \ t?, fie ca index ASCII? \ x0A \ x0D \ x09?.
Următoarea evidențiere face ca valorile noastre să fie în siguranță pentru instrucțiunile SQL.
De data aceasta nu vrem să scăpăm de nimic, vrem doar să nu avem decât o valoare numerică valabilă - fie că este un întreg sau un punct plutitor.
S-ar putea să fi observat linia 10, și probabil că se întreba care este scopul lui. Cu câțiva ani în urmă, am lucrat la un sistem de logare a centrului de call-uri pe care îl folosea variabilă + = 0;
pentru a asigura valori numerice. De ce sa făcut asta, nu pot spune sincer? cu excepția cazului în care înainte de PHP 4 a fost modul în care am făcut-o ?! Poate că cineva care citește poate scoate ceva lumină asupra subiectului. În afară de asta, dacă tu, ca și mine, ai venit peste o linie ca asta în sălbăticie, veți ști ce încearcă să facă.
Mutarea înainte; linii 11 și 12 sunt tot ceea ce avem nevoie pentru a pregăti valorile numerice de intrare pentru SQL. Ar trebui să spun, a avut șirul de intrare $ number_i
conținea orice caractere non-numerice in fata sau la stanga din cele numerice? valorile noastre $ NUMBER_A
, $ number_b
și $ number_c
ar fi totul este egal cu 0.
Vom folosi floatval
să ne curățăm numerele de intrare; PHP imprimă numai zecimale atunci când acestea există în valoarea de intrare - prin urmare, imprimarea acestora într-o instrucțiune SQL nu va cauza erori dacă nu a fost introdusă nici o zecimală. Atâta timp cât codul nostru de server este în siguranță, putem lăsa validarea mai fină a codului nostru de client.
Înainte de a trece la o listă finală pentru PHP, vom examina finala cod
evidențiați boxul boolean.
Ca și echivalentul C ++, un boolean în PHP este într-adevăr un întreg. Ca și în, True + True = Two. Există nenumărate moduri de a traduce un șir de intrări într-un tip boolean, personalul meu favorit: șirul cu litere mici conține cuvântul adevărat?
Cu toții vă puteți avea propriile metode preferate; șirul de intrare este explicit egal? true? sau este șirul de intrare? 1? etcetera? ceea ce este important este că valoarea care vine, indiferent cum ar putea arăta ea, este reprezentată de un boolean (sau întreg) înainte de ao folosi.
Filozofia mea personală este pur și simplu: dacă X este
Adevărat
saufals
, atunciX
este un boolean. Voi scrie cu blândețe tot codul pe care ar fi trebuit să îl revizuiesc mai târziu cu Boolean și nu scurt, int, tinyint sau orice altceva care nu este boolean. Ceea ce se întâmplă pe metal nu este îngrijorarea mea ceea ce arata unui om este mult mai important.
Deci, ca și în cazul numerelor și șirurilor, booleanii noștri sunt garantați în siguranță din momentul în care îi atragem în scenariul nostru. În plus, codul nostru de igienă nu are nevoie de linii suplimentare.
Acum, că ne-am protejat SQL-ul de la injecții, și ne-am asigurat că numai un login POST poate funcționa în mod corespunzător cu scenariul nostru, suntem gata să implementăm funcția de trimitere a recenziilor.
Clientul nostru dorește să permită utilizatorilor cu permisiunea de revizuire să-și formateze contribuțiile ca HTML obișnuit. Acest lucru ar părea suficient de simplu, dar știm de asemenea că adresele de e-mail sunt zece la penny, iar conturile din librărie sunt create programabil - deci în interesul tuturor celor pe care îi vom asigura doar etichetele pe care le spunem trec.
Deciderea modului în care verificăm examinarea primită poate părea descurajantă. Specificația HTML are o serie de etichete destul de sănătoase, dintre care multe suntem bucuroși să le permitem.
Atâta timp cât s-ar părea sarcina, eu îi sfătuiesc pe toți - alege ce să permită și niciodată ce să nege. Limbi de marcare pentru browsere și server toate
aderați la XML, cum ar fi structurarea, astfel încât să ne bazăm codul asupra faptului fundamental că codul executabil trebuie să fie înconjurat de etichete înclinate în unghi.
Acordat, există mai multe moduri în care putem obține același rezultat. Pentru acest articol voi descrie o posibilă conductă de exprimare regulată:
Aceste expresii regulate nu vor produce o ieșire impecabilă, dar în majoritatea cazurilor ar trebui să facă o treabă aproape elegantă.
Să aruncăm o privire la expresia regulată pe care o vom folosi în PHP. Veți observa că două mese au fost declarate. $ safelist_review
și $ safelist_comment
- acest lucru este astfel încât să putem folosi aceleași funcții pentru a valida recenzii și mai târziu, comentarii:
? și aici este principala funcție pe care o vom apela pentru a dezinstala datele revizuirii și comentariilor:
Parametrii de intrare, am subliniat roșu și albastru. $ intrare
este datele brute prezentate de utilizator și de utilizator lista $
este o referință la matricea de expresii; $ safelist_review
sau $ safelist_comment
în funcție de tipul de depunere pe care dorim să îl validăm.
Funcția returnează versiunea reformatată a datelor trimise - toate etichetele nu face treceți oricare dintre expresiile regulate din lista aleasă sunt convertite în echivalente codate HTML. Ceea ce face cel mai simplu <
și >
în <
și >
alte caractere sunt modificate, dar niciunul dintre acestea nu reprezintă o amenințare la adresa securității pentru clientul nostru sau pentru utilizatori.
Notă: Funcțiile: cleanWhitespace și getTags sunteți inclusă în fișierele sursă ale articolului.
Ai fi corect să presupunem că tot ce am făcut cu adevărat este ajutat să supraviețuiască esteticii paginilor site-ului nostru și nu am făcut totul pentru a proteja securitatea utilizatorului. Există încă o gaură de securitate destul de enormă, deși: JavaScript de injecție.
Acest defect particular ar putea fi stabilit de câteva expresii regulate și / sau modificări ale celor pe care le folosim deja. Expresia noastră regulată de ancoră permite doar? /? ?,? h? ? și ?#? ? valori ca href
atribut - care este într-adevăr doar un exemplu de soluție. Navigatorii, dincolo de bord înțeleg, o mare varietate de script vizibil
atribute, cum ar fi onClick
, onLoad
si asa mai departe.
În esență, am creat o problemă spinoasă pentru noi înșine. Am vrut să permitem HTML, dar acum avem o listă aproape nesfârșită de cuvinte cheie care trebuie eliminate. Există, bineînțeles, o metodă mai puțin decât perfectă, dar destul de rapid scrisă pentru a face acest lucru:
La reflecție, ai fi absolut justificată să întrebi: De ce nu am folosit doar BBCode sau Textil sau? ??
Eu însumi, dacă aș avea de-a face cu procesarea marcajului, aș putea merge chiar și pentru mersul XML. După toate datele primite ar trebui să fi XML valid.
Totuși, acest articol nu este menit să ne învețe cum să regexăm, cum să procedăm PHP sau cum să scriem ceva într-o anumită limbă. Motivul care stă în spatele ei este pur și simplu, nu lăsa nici o ușă închisă.
Deci, să terminăm atunci; cu o revizuire rapidă a ceea ce ne-am uitat:
Desigur, acest articol nu te-a echipat cu nici un proiect de pe raft. Scopul principal al scrisului meu nu a fost acela de a sparge designerii care codifică sau de a împușca munca codificatorilor oriunde, ci de a încuraja toată lumea să autorizeze un cod robust de la inițierea. Acestea fiind spuse, intenționez să revizuiesc anumite elemente ale acestui articol mai detaliat mai târziu.
Până atunci, codul sigur!