Un exemplu simplu PHP și AJAX. Sarcină de testare pentru un dezvoltator PHP pe un test de succes PHP pentru perioada de probă


În lista celor mai frecvente zece tipuri de atacuri conform OWASP, primele două locuri sunt ocupate de atacuri cu injecție de cod și XSS (cross-site scripting). Ele merg mână în mână, deoarece XSS, ca și alte tipuri de atacuri, se bazează pe succesul atacurilor prin injecție. Sub acest nume este ascunsă o întreagă clasă de atacuri, timp în care datele sunt injectate într-o aplicație web pentru a o forța să execute sau să interpreteze cod rău intenționat în modul în care dorește atacatorul. Astfel de atacuri includ, de exemplu, XSS, SQL Injection, Header Injection, Code Injection și Full Path Disclosure. Și aceasta este doar o mică parte.


Atacurile prin injecție sunt o poveste de groază pentru toți programatorii. Sunt cele mai comune și de succes datorită varietății, amplorii și (uneori) complexității protejării împotriva lor. Toate aplicațiile trebuie să preia date de undeva. XSS și UI Redress sunt deosebit de comune, așa că le-am dedicat capitole separate și le-am separat de clasa generală.


OWASP oferă următoarea definiție a atacurilor prin injecție:


Oportunitățile de injectare - cum ar fi SQL, OS și LDAP - apar atunci când interpretul primește date care nu sunt de încredere ca parte a unei solicitări de comandă. Datele rău intenționate pot păcăli interpretul să execute anumite comenzi sau să acceseze date neautorizate.

injecție SQL

Injecția SQL este cea mai comună și extrem de periculoasă formă de atacuri prin injecție. Este dificil să supraestimați gravitatea acestei amenințări, așa că este extrem de important să înțelegeți ce afectează succesul atacurilor și cum să vă protejați de ele.


Deci, datele sunt încorporate într-o aplicație web și apoi utilizate în interogări SQL. De obicei, acestea provin din surse de intrare nesigure, cum ar fi formularele web. Cu toate acestea, injecția poate fi efectuată și din alte locuri, cum ar fi baza de date în sine. Programatorii cred adesea că baza lor de date este complet sigură, fără să realizeze că doar pentru că a fost sigură o dată, nu înseamnă că va fi sigură în viitor. Datele din baza de date ar trebui considerate nesigure până la proba contrarie, adică până când au trecut testul.


Dacă atacul are succes, atacatorul poate manipula interogarea SQL astfel încât să efectueze operațiuni pe baza de date care nu sunt intenționate de dezvoltatori.


Uită-te la această cerere:


$db = mysqli nou ("localhost", "nume utilizator", "parolă", "storedb"); $rezultat = $db->query("SELECT * FROM tranzacții WHERE user_id = " . $_POST["user_id"]);

Există o serie de bug-uri aici. În primul rând, nu am verificat conținutul datelor POST pentru a vedea dacă user_id a fost corect. În al doilea rând, lăsăm o sursă neîncrezătoare să ne spună ce user_id să folosim: un atacator poate introduce orice user_id valid. Poate că era conținut într-un câmp de formular ascuns, pe care l-am considerat sigur pentru că nu poate fi editat (uitând în același timp că atacatorii pot introduce orice date). În al treilea rând, nu am scăpat de user_id și l-am transmis ca parametru legat la interogare, ceea ce permite atacatorului să injecteze șiruri arbitrare care vor manipula interogarea SQL, având în vedere că nu am putut-o verifica de la început.


Aceste trei omisiuni sunt foarte frecvente în aplicațiile web.


În ceea ce privește încrederea în baza de date, imaginați-vă că căutăm tranzacții folosind câmpul user_name. Numele sunt variate și pot conține ghilimele. Să presupunem că un atacator a stocat o valoare de șir încorporată într-unul dintre numele de utilizator. Când folosim din nou această valoare într-una dintre următoarele solicitări, va manipula șirul de interogare, deoarece am considerat baza de date ca o sursă de încredere și nu am izolat și restricționat cererea compromisă.


De asemenea, acordați atenție unui alt factor de implementare SQL: stocarea persistentă nu trebuie păstrată întotdeauna pe server. HTML 5 acceptă utilizarea unei baze de date pe partea client, unde interogările pot fi trimise folosind SQL și JavaScript. Există două API-uri pentru aceasta: WebSQL și IndexedDB. În 2010, W3C a descurajat alegerea WebSQL; este acceptat de browserele WebKit care folosesc SQLite ca backend. Cel mai probabil, suportul va rămâne de dragul compatibilității cu versiunea anterioară, chiar și în ciuda recomandării W3C. După cum sugerează și numele, acest API acceptă interogări SQL, ceea ce înseamnă că poate fi ținta atacurilor prin injecție. IndexedDB este o alternativă mai nouă, o bază de date NoSQL (nu necesită utilizarea de interogări SQL).

Exemple de injecție SQL

Manipularea interogărilor SQL poate avea următoarele obiective:

  1. Scurgeri de date.
  2. Dezvăluirea informațiilor stocate.
  3. Manipularea informațiilor stocate.
  4. Bypass de autorizare.
  5. Injecție SQL pe partea clientului.

Protecție prin injecție SQL

Protecția prin injecție SQL se bazează pe principiul separării. Înainte de a utiliza datele din interogare, trebuie să verificați dacă forma lor este corectă. De asemenea, trebuie să izolați datele înainte de a le include în interogare sau să le includeți ca parametru de tranziție.

Examinare

Repet: toate datele care nu au fost create explicit în codul sursă PHP al solicitării curente sunt nesigure. Verificați-le cu rigurozitate și respingeți orice nu trece de verificări. Nu încercați să „remediați” datele, puteți face doar modificări minore, cosmetice, la format.


Greșelile comune includ validarea datelor pentru utilizare ulterioară (de exemplu, pentru afișare sau calcule) și nevalidarea câmpurilor din baza de date în care vor fi stocate informațiile rezultate.

Ecranarea

Cu extensia mysqli, puteți izola toate datele incluse într-o interogare SQL. Acest lucru este realizat de funcția mysqli_real_escape_string(). Extensia pgsql pentru PostgresSQL oferă funcțiile pg_escape_bytea() , pg_escape_identifier() , pg_escape_literal() și pg_escape_string(). În extensia mssql (Microsoft SQL Server) nu există funcții de izolare, iar abordarea addslashes() este ineficientă - veți avea nevoie de un .


Pentru a vă complica și mai mult viața, voi spune că nu aveți dreptul să greșiți la izolarea datelor introduse în cerere. O ratare și ești vulnerabil la atac.


Rezuma. Ecranarea nu este cel mai bun mod protecţie. Ar trebui folosit ca ultimă soluție. Poate fi necesar dacă biblioteca de baze de date pe care o utilizați pentru abstracție vă permite să configurați interogări simple SQL sau părți de interogare fără legarea forțată a parametrilor. În alte cazuri, este mai bine să evitați cu totul izolarea. Această abordare este complexă, predispusă la erori și variază în funcție de extensia bazei de date.

Interogări parametrizate (expresii prefabricate)

Parametizarea sau legarea parametrilor este modalitatea recomandată de a crea interogări SQL. Toate biblioteci bune DB-urile îl folosesc implicit. Iată un exemplu de utilizare a extensiei PDO pentru PHP:


if(ctype_digit($_POST["id"]) && is_int($_POST["id"])) ( $validatedId = $_POST["id"]; $pdo = new PDO ("mysql:store.db") ; $stmt = $pdo->prepare("SELECT * FROM tranzacții WHERE user_id = :id"); $stmt->bindParam(":id", $validatedId, PDO::PARAM_INT); $stmt->execute() ;) else ( // respinge valoarea id și informează utilizatorul despre eroare )

Metoda bindParam(), disponibilă pentru expresiile PDO, vă permite să legați parametrii la „substituenți” furnizați într-o expresie pregătită. Această metodă acceptă parametrii tipurilor de date de bază, cum ar fi PDO::PARAM_INT , PDO::PARAM_BOOL , PDO::PARAM_LOB și PDO::PARAM_STR . Pentru PDO::PARAM_STR aceasta este valoarea implicită, dacă nu se specifică altfel, așa că rețineți și pentru alte valori!


Spre deosebire de izolarea manuală, legarea parametrilor (sau o altă metodă utilizată de biblioteca dumneavoastră de baze de date) va izola corect datele legate automat, astfel încât să nu fie nevoie să vă amintiți ce funcție să utilizați. De asemenea, legarea consecventă a parametrilor este mult mai fiabilă decât încercarea de a vă aminti să izolați totul manual.

Implementarea principiului privilegiului minim

Întreruperea unei injecții SQL de succes este la fel de importantă ca și prevenirea ei completă. Când un atacator are ocazia de a executa interogări SQL, o va face ca un anumit utilizator al bazei de date. Principiul cel mai mic privilegiu asigură că toți utilizatorii au doar acele privilegii care sunt absolut necesare pentru a-și îndeplini sarcinile.


Dacă utilizatorul are privilegii largi, atunci atacatorul poate renunța la tabele și poate modifica privilegiile altor utilizatori, executând noi injecții SQL în numele lor. Pentru a preveni acest lucru, nu accesați niciodată baza de date dintr-o aplicație web ca root, administrator sau alt utilizator cu privilegii mari.


O altă aplicare a principiului este separarea rolurilor de citire și scriere a datelor în baza de date. Selectați un utilizator cu permisiuni numai pentru scriere și celălalt cu permisiuni numai pentru citire. Dacă atacul este îndreptat către utilizatorul care „citește”, atunci atacatorul nu va putea să manipuleze datele din tabel sau să le scrie. Este posibil să restricționați accesul și mai restrâns, reducând astfel impactul atacurilor de succes cu injecție SQL.


Multe aplicații web, în ​​special cele open source, sunt concepute pentru a avea un singur utilizator de bază de date al cărui nivel de privilegii nu este aproape sigur verificat niciodată. Deci, nu uitați de acest punct și nu încercați să rulați aplicații sub un cont de administrator.

Injectare de cod (cunoscută sub numele de Remote File Inclusion)

Injecția de cod este orice tehnică care permite unui atacator să adauge cod sursă unei aplicații web, astfel încât să poată fi interpretat și executat. În același timp, nu vorbim despre injectarea de cod în partea clientului, de exemplu, în JavaScript, atacurile XSS sunt deja folosite aici.


Puteți injecta cod sursă direct dintr-o sursă de intrare neîncrezătoare sau puteți solicita aplicației web să îl încarce din sistemul de fișiere local sau dintr-o resursă externă, cum ar fi o adresă URL. Când codul este injectat ca urmare a includerii unei surse externe, aceasta este de obicei denumită includere fișier la distanță (RFI), deși RFI-ul în sine este întotdeauna destinat să injecteze cod.


Principalele motive pentru implementarea codului:

  • bypass de validare a intrării,
  • injectarea de date de intrare nesigure în orice context în care acestea vor fi considerate cod PHP,
  • spargerea securității depozitelor de cod sursă,
  • dezactivarea avertismentelor despre încărcarea bibliotecilor terță parte,
  • reconfigurarea serverului pentru a transmite fișiere non-PHP interpretului PHP.

Acordați o atenție deosebită ultimului punct: în acest caz, utilizatorii nesiguri pot încărca orice fișiere pe server.

Exemple de injecție de cod

LA Setul PHPținte pentru injectarea de cod, astfel încât acest tip de atac este în fruntea listei de urmărire a oricărui programator.

Includerea fișierului

Cele mai evidente ținte pentru injectarea codului sunt funcțiile include() , include_once() , require() și require_once(). Dacă intrarea neîncrezătoare permite determinarea parametrului de cale transmis acestor funcții, atunci va fi posibil să se controleze de la distanță ce fișier să includă. Trebuie remarcat faptul că fișierul inclus nu trebuie să fie un fișier PHP real, este permis orice format de fișier capabil să stocheze date text (adică aproape fără restricții).


Parametrul cale poate fi, de asemenea, vulnerabil la traversarea directorului sau atacurile de includere a fișierelor de la distanță. Folosirea ../ sau... în cale îi permite unui atacator să navigheze la aproape orice fișier la care are acces un proces PHP. De asemenea, în configurația PHP implicită, funcțiile de mai sus acceptă o adresă URL, cu excepția cazului în care allow_url_include este dezactivată.

Examinare

Funcția PHP eval() preia un șir de cod PHP pentru a fi executat.

Injecție cu expresie regulată

Funcția PCRE (expresie regulată compatibilă cu Perl) preg_replace() în PHP acceptă modificatorul e (PREG_REPLACE_EVAL). Aceasta înseamnă un șir de înlocuire, care, după înlocuire, va fi considerat cod PHP. Și dacă în această linie există intrări care nu sunt de încredere, atunci vor putea injecta codul PHP executabil.

Logica de includere a fișierelor defectuoasă

Aplicațiile web, prin definiție, includ fișierele necesare pentru a servi orice solicitare. Dacă este exploatat de defecte în logica de rutare, managementul dependențelor, încărcarea automată și alte procese, manipularea căii de solicitare sau a parametrilor acesteia va determina serverul să includă fișiere locale specifice. Deoarece o aplicație web nu este concepută pentru a gestiona astfel de manipulări, consecințele pot fi imprevizibile. De exemplu, aplicația va evidenția fără să vrea rute destinate numai utilizării în Linie de comanda. Sau expuneți alte clase ai căror constructori îndeplinesc sarcini ( clase mai bune nu proiectați așa, dar tot se întâmplă). Oricare dintre aceste scenarii poate interfera cu operațiunile de backend ale aplicației, permițând manipularea datelor sau un atac DOS asupra operațiunilor care consumă mult resurse care nu implică acces direct.

Sarcini de injectare a codului

Gama de sarcini este extrem de largă, întrucât acest tip de atac permite executarea oricărui cod PHP la alegerea atacatorului.

Apărări împotriva injectării codului

injecție de comandă

Exemple de injecție de comandă

Apărări împotriva injecției de comandă

Injectare de jurnal (cunoscută sub numele de injectare de fișiere de jurnal)

Multe aplicații colectează jurnalele, iar utilizatorii autorizați le vizualizează adesea printr-o interfață HTML. Prin urmare, jurnalele sunt una dintre principalele ținte ale atacatorilor care doresc să mascheze alte atacuri, să-i înșele pe cei care văd jurnalele și apoi chiar să atace utilizatorii aplicației de monitorizare care citește și analizează jurnalele.


Vulnerabilitatea jurnalelor depinde de mecanismele de control asupra înregistrării jurnalelor, precum și de tratarea datelor de jurnal ca sursă nesigură atunci când se vizualizează și se analizează înregistrările.


Un sistem simplu de înregistrare poate scrie într-un fișier șiruri de text cu file_put_contents() . De exemplu, un programator înregistrează încercările de autorizare eronate ca șiruri de următorul format:


sprintf(„Încercare eșuată de conectare de către %s”, $nume utilizator);

Ce se întâmplă dacă atacatorul folosește numele „AdminnSuccessful login by Adminn” în formular?


Dacă această linie este introdusă în jurnal din date de intrare care nu sunt de încredere, atunci atacatorul va masca cu succes încercarea eșuată de autentificare cu un eșec inocent de a introduce parola de administrator. Suspectul datelor va scădea și mai mult dacă adăugați o încercare de autorizare reușită.


Ideea aici este că atacatorul poate adăuga tot felul de intrări în jurnal. De asemenea, puteți încorpora un vector XSS și chiar caractere care îngreunează citirea intrărilor de jurnal în consolă.

Sarcini de injectare în jurnal

Unul dintre obiectivele implementării este interpreții de format de jurnal. Dacă instrumentul de analiză utilizează expresii obisnuite pentru a analiza intrările de jurnal, pentru a le împărți în părți și a le împrăștia pe diferite câmpuri, apoi puteți crea și injecta un șir care va forța expresiile regulate să selecteze câmpurile încorporate în loc de cele corecte. De exemplu, această intrare poate fi sursa mai multor probleme:


$username = "iamnothacker! la Luni Ian 01 00:00:00 +1000 2009"; sprintf(„Încercare eșuată de conectare de către %s la %s”, $nume utilizator,)

Atacurile mai sofisticate de injectare a jurnalelor se bazează pe atacurile de traversare a directoarelor pentru a afișa jurnalul în browser. În condițiile potrivite, injectarea codului PHP într-un mesaj de jurnal și deschiderea unui fișier jurnal într-un browser va injecta cu succes un cod bine formatat și executat la voința atacatorului. Și dacă vine vorba de execuția PHP rău intenționat pe server, atunci nu putem decât să sperăm la eficacitatea separării apărării, care poate reduce daunele.

Protectie la injectie busteni

Cel mai simplu mod de a filtra toate mesajele de jurnal externe este cu o listă albă. Să presupunem că limităm setul de caractere doar la numere, litere și spații. Mesajele care conțin caractere ilegale sunt considerate corupte. Apoi apare o intrare în jurnal despre o potențială încercare de a implementa un fișier jurnal. Aceasta este o apărare ușoară pentru jurnalele de text simple în care introducerea neîncrezătoare nu poate fi evitată.


A doua metodă de protecție este de a converti porțiuni de date de intrare nesigure folosind un sistem precum base64 , care acceptă un set limitat de caractere, permițând în același timp stocarea în forma text informatii variate.

Parcursul drumului (cunoscut sub numele de traversare director)

Atacurile transversale sunt încercări de a afecta operațiunile de citire sau scriere a fișierelor din backend-ul unei aplicații web. Acest lucru se realizează prin injectarea de parametri care permit manipularea căilor fișierelor implicate în operațiunile de backend. Deci, acest tip de atac facilitează divulgarea informațiilor și injectarea fișierelor locale/la distanță.


Vom lua în considerare astfel de atacuri separat, dar traversarea căii este baza succesului lor. Deoarece funcțiile descrise mai jos sunt specifice manipulării căilor de fișiere, este de menționat că multe funcții PHP nu acceptă căile de fișiere în sensul obișnuit. În schimb, funcții precum include() sau file() acceptă un URI.


Pare complet nenatural. Dar aceasta înseamnă că următoarele două apeluri de funcții sunt echivalente, care folosesc căi absolute (de exemplu, nu se bazează pe încărcarea automată a căilor relative).


include('/var/www/vendor/library/Class.php'); include('file:///var/www/vendor/library/Class.php');

Faptul este că calea relativă este procesată lateral (setarea include_path în php.ini și încărcătoarele automate disponibile). În astfel de cazuri, funcțiile PHP sunt deosebit de vulnerabile la multe forme de manipulare a parametrilor, inclusiv File URI Scheme Substitution, unde un atacator poate injecta un URI HTTP sau FTP dacă date nede încredere sunt încorporate la începutul căii fișierului. Vom vorbi mai multe despre acest lucru în secțiunea despre atacurile de includere a fișierelor la distanță, dar pentru moment, ne vom concentra pe ocolirea căilor sistemului de fișiere.


Această vulnerabilitate implică schimbarea căii pentru a accesa un alt fișier. Acest lucru se realizează de obicei prin injectarea unei serii de secvențe ../ în argument, care este apoi atașat la funcții sau inserat în întregime în funcții precum include() , require() , file_get_contents() și chiar mai puțin suspecte (pentru unele) funcții ca DOMDocument: :load() .


Folosind secvența ../, atacatorul forțează sistemul să revină în directorul părinte. Deci calea /var/www/public/../vendor duce de fapt la /var/www/vendor . Secvența ../ after / public ne duce înapoi la directorul părinte, adică / var/www . Astfel, atacatorul obține acces la fișierele aflate în afara directorului / public accesibil de pe serverul web.


Desigur, parcurgerea căii nu se limitează doar la întoarcere. Este posibil să injectați noi elemente de cale pentru a accesa directoarele copil care nu sunt accesibile din browser din cauza setărilor de restricții din .htaccess. Operațiunile PHP pe sistemul de fișiere nu se referă la configurarea controlului accesului la fișierele și directoarele non-publice de pe serverul web.

Exemple de traversare a căii

Apărări împotriva traversării căii

injectare XML

În ciuda introducerii JSON ca mijloc ușor de transmitere a datelor între un server și un client, XML rămâne o alternativă populară, iar API-urile pentru servicii web îl acceptă adesea alături de JSON. XML este folosit și pentru schimbul de date folosind scheme XML: RSS, Atom, SOAP și RDF etc.


XML este omniprezent: poate fi găsit în serverele de aplicații web, browsere (ca format preferat pentru cererile și răspunsurile XMLHttpRequest) și extensiile de browser. Având în vedere omniprezența și analiza implicită de către un analizator atât de popular precum libxml2 utilizat de PHP în DOM și în extensiile SimpleXML și XMLReader, XML a devenit o țintă pentru atacurile prin injecție. Atunci când un browser participă activ la un schimb XML, trebuie să se țină cont de faptul că prin XSS, utilizatorii autorizați pot transmite cereri XML care sunt de fapt create de atacatori.

Injecție de entitate XML externă (XXE)

Astfel de atacuri există deoarece bibliotecile de analiză XML acceptă adesea utilizarea referințelor de entități personalizate. Veți face cunoștință cu complementul XML standard al entităților, este folosit pentru a reprezenta caractere speciale marcare ca > , < ; și '. XML vă permite să extindeți setul de entități standard prin definirea de entități personalizate prin documentul XML însuși. Ele pot fi definite prin includerea lor directă într-un DOCTYPE opțional. Valoarea extinsă pe care o reprezintă se poate referi la o resursă externă care trebuie inclusă. Atacurile XXE au devenit populare tocmai datorită capacității XML obișnuit de a stoca link-uri personalizate care pot crește datorită conținutului resurselor externe. În circumstanțe normale, intrarea neîncrezătoare nu ar trebui să interacționeze niciodată cu sistemul nostru în moduri neașteptate. Și majoritatea programatorilor XXE aproape sigur nu anticipează atacurile XXE, ceea ce este deosebit de îngrijorător.


Să definim o nouă entitate personalizată, inofensivă, de exemplu:


]>

Un document XML cu această definiție se poate referi acum la o entitate oriunde sunt permise entități:


]> Acest rezultat este

Când un parser XML precum PHP DOM interpretează acest XML, va analiza această entitate personalizată de îndată ce documentul este încărcat. Prin urmare, la solicitarea textului corespunzător, acesta va returna următoarele:


Acest rezultat este complet inofensiv


În mod clar, entitățile personalizate au avantajul de a reprezenta text repetitiv și XML cu nume de entități mai scurte. Se întâmplă adesea ca XML să urmeze o anumită gramatică, iar entitățile personalizate facilitează editarea. Cu toate acestea, având în vedere neîncrederea noastră în inputul extern, trebuie să fim foarte atenți cu tot XML pe care îl consumă aplicația noastră. De exemplu, aceasta nu este deloc o variantă sigură:


]> &harmless;

În funcție de conținutul solicitat fișier local datele pot fi folosite la extinderea unei entități. Și apoi conținutul bogat poate fi extras din parserul XML și inclus în datele de ieșire ale aplicației web pentru analiza de către atacator. De exemplu, pentru dezvăluirea de informații. Fișierul extras va fi interpretat ca XML, deși nu există caractere speciale care să declanșeze o astfel de interpretare. Acest lucru limitează sfera dezvăluirii conținutului fișierelor locale. Dacă fișierul este interpretat ca XML, dar nu conține XML valid, atunci cel mai probabil vom primi o eroare, care va împiedica dezvăluirea conținutului. Cu toate acestea, în PHP este disponibil un truc bun pentru a ocoli limita de scară, astfel încât solicitările HTTP de la distanță afectează aplicația web chiar dacă răspunsul returnat nu poate fi transmis înapoi atacatorului.


Există trei metode comune pentru analizarea și utilizarea XML în PHP: PHP DOM, SimpleXML și XMLReader. Toți folosesc extensia libxml2 și suportul pentru entități externe este activat implicit. În consecință, PHP are o vulnerabilitate implicită de atac XXE, care este foarte ușor de ratat când luăm în considerare securitatea unei aplicații web sau a unei biblioteci care utilizează XML.


De asemenea, nu uitați că XHTML și HTML 5 pot fi serializate ca XML valid. Aceasta înseamnă că unele pagini XHTML sau HTML 5 serializat în XML pot fi analizate ca XML folosind DOMDocument::loadXML() în loc de DOMDocument::loadHTML() . Această utilizare a unui parser XML este, de asemenea, vulnerabilă la injectarea de entități XML externe. Amintiți-vă că libxml2 nici măcar nu recunoaște HTML 5 DOCTYPE încă, așa că nu îl poate valida ca XHTML DOCTYPES.

Exemple de încorporare a entităților XML externe

Conținutul fișierului și dezvăluirea

Mai sus, am analizat un exemplu de dezvăluire a informațiilor, observând că o entitate XML personalizată se poate referi la un fișier extern.


]> &harmless;

În acest caz, entitatea personalizată va fi extinsă cu conținutul fișierelor. Deoarece toate aceste solicitări sunt făcute local, acest lucru vă permite să dezvăluiți conținutul tuturor fișierelor pe care aplicația le poate citi. Adică, atunci când entitatea extinsă este inclusă în datele de ieșire ale aplicației, atacatorul va putea examina fișierele care se află în acces privat. Adevărat, în acest caz există o limitare serioasă: fișierele trebuie să fie fie în format XML, fie într-un format care să nu conducă la o eroare de analiză XML. Dar ideea este că această limitare poate fi complet ignorată în PHP:


]> &harmless;

PHP vă oferă acces la wrapper ca URI, unul dintre protocoalele acceptate de funcțiile standard ale sistemului de fișiere: file_get_contents() , require() , require_once() , file() , copy() și multe altele. Wrapper-ul PHP acceptă un număr de filtre care pot fi aplicate unei anumite resurse, astfel încât rezultatele să fie returnate de un apel de funcție. În exemplul de mai sus, aplicăm filtrul convert.base-64-encode la fișierul țintă pe care dorim să-l citim.


Aceasta înseamnă că un atacator poate citi orice disponibil fișier PHP, indiferent de formatul textului. Este suficient să decodați pur și simplu datele care vin din aplicație și apoi să le disecați cu impunitate. Deși acest lucru nu dăunează direct utilizatorilor finali sau backend-ului aplicației, le permite atacatorilor să privească bine structura aplicației în încercarea de a găsi alte vulnerabilități. Mai mult, riscul ca atacatorii să fie detectați este minim.

Bypass control acces

Acces controlat căi diferite. Deoarece atacurile XXE sunt efectuate pe backend-ul aplicației web, nu va fi posibilă utilizarea sesiunii utilizatorului actual. Dar un atacator poate încă ocoli controlul accesului la backend folosind solicitări de la serverul local. Luați în considerare acest control primitiv al accesului:


if (isset($_SERVER["HTTP_CLIENT_IP"]) || isset($_SERVER["HTTP_X_FORWARDED_FOR"]) || !in_array(@$_SERVER["REMOTE_ADDR"], array("127.0.0.1", "::1") ",))) ( header ("HTTP/1.0 403 Interzis"); ieșire ("Nu aveți voie să accesați acest fișier."); )

Această bucată de PHP, ca și o multitudine de altele asemenea, restricționează accesul la anumite fișiere PHP de pe serverul local, adică localhost. Cu toate acestea, un atac XXE pe front-end-ul aplicației oferă atacatorului acreditările exacte necesare pentru a ocoli acest control de acces, deoarece toate cererile HTTP către parserul XML vor fi făcute de la localhost.


]> &harmless;

Chiar dacă navigarea în jurnal s-ar limita la solicitări locale, un atacator ar putea în continuare să obțină jurnalele. Același lucru este valabil și pentru interfețele de întreținere sau administrare, accesul la care este restricționat în acest fel.

Atacurile DOS

Pentru atacurile DOS, puteți folosi aproape orice dictează consumul de resurse de server. Prin injectarea unei entități XML externe, un atacator este capabil să facă cereri HTTP arbitrare care, în condițiile potrivite, epuizează resursele serverului.


Mai târziu, vom vorbi despre alte posibile utilizări DOS ale atacurilor XXE din punctul de vedere al extinderii entităților XML.

Protecție împotriva injectării de entități XML externe

Aceste atacuri sunt foarte populare, așa că vei fi surprins cât de ușor este să te aperi împotriva lor. Deoarece DOM, SimpleXML și XMLReader se bazează pe libxml2, tot ce puteți face este să utilizați funcția libxml_disable_entity_loader() pentru a dezactiva utilizarea entităților externe. Adevărat, acest lucru nu va dezactiva entitățile personalizate predefinite în DOCTYPE, deoarece nu folosesc resurse externe care necesită o solicitare sau o operație HTTP în Sistemul de fișiere.


$oldValue = libxml_disable_entity_loader(true); $dom = nou DOMDocument(); $dom->loadXML($xml); libxml_disable_entity_loader($oldValue);

Acest lucru trebuie făcut pentru toate operațiunile care implică încărcarea XML din șiruri, fișiere sau URI-uri la distanță.


Acolo unde o aplicație nu are nevoie niciodată de entități externe și pentru majoritatea solicitărilor sale, puteți dezactiva complet încărcarea resurselor externe la un nivel mai global. În majoritatea cazurilor, acest lucru este mult de preferat pentru a determina toate „punctele de încărcare XML”, având în vedere că multe biblioteci au vulnerabilități inerente la atacurile XXE:


libxml_disable_entity_loader(true);

Nu uitați să returnați TRUE de fiecare dată când activați temporar încărcarea resurselor externe. Este posibil să aveți nevoie de el pentru sarcini inofensive, cum ar fi conversia Docbook XML în HTML, unde aplicarea stilurilor XSL depinde de entitățile externe.


Cu toate acestea, dezactivarea libxml2 nu este un panaceu. Analizați alte extensii și biblioteci PHP care analizează sau procesează în alt mod XML pentru a găsi „comutatoarele” lor pentru utilizarea entităților externe.


Dacă acest lucru nu este posibil, atunci verificați suplimentar dacă documentul XML declară un DOCTYPE. Dacă da, și dacă entitățile externe sunt, de asemenea, dezactivate, atunci pur și simplu aruncați documentul XML, interzicând accesul XML neîncrezat la analizatorul potențial vulnerabil și înregistrându-l ca un posibil atac. Acesta este un pas necesar, deoarece nu vor exista alte semne - fără erori, fără excepții. Construiți această verificare în validarea dvs. normală de intrare. Dar această metodă este departe de a fi perfectă, așa că este foarte recomandat să abordăm problema entităților externe la rădăcină.


/** * Încercați o detecție rapidă */ $collapsedXML = preg_replace("/[:space:]/", "", $xml); if(preg_match("/

De asemenea, este de preferat să ștergeți imediat datele suspecte care pot fi rezultatul unui atac. De ce să continuați să lucrați la ceva care pare periculos? Deci, combinația dintre cele două măsuri de mai sus vă permite să ignorați în prealabil datele evident rău intenționate, protejându-vă în același timp în cazul în care datele nu pot fi șterse (de exemplu, dacă acestea sunt biblioteci terțe). De asemenea, trebuie să ștergeți datele deoarece libxml_disable_entity_loader () nu dezactivează toate entitățile personalizate, ci doar pe cele care se referă la resurse externe. Aceasta lasă posibilitatea unui atac XML Entity Expansion.

Extensie de entitate XML

Acest atac este similar în multe privințe cu atacul de injecție de entități XML. Dar, în acest caz, accentul este pus pe un atac DOS cu încercarea de a epuiza resursele mediului de server al aplicației țintă. În DOCTYPE XML, este creată o definiție personalizată de entitate, care, de exemplu, poate genera structuri XML în memorie mult mai mari decât cea originală. Acest lucru umple memoria și reduce eficiența serverului. Acest atac se aplică și serializării HTML 5 XML dacă aceasta din urmă nu este recunoscută ca HTML de extensia libxml2.

Exemple de extensii de entitate XML

Există mai multe modalități de a extinde entitățile XML personalizate pentru epuizarea dorită a resurselor serverului.

Extensie de entitate generică

Un alt nume este „atac cu mărire pătrată”. O entitate personalizată este definită ca un șir foarte lung. Dacă îl folosești în mod repetat într-un document, atunci crește de fiecare dată, ca urmare, structura XML consumă mult mai multă RAM în comparație cu XML-ul original.


]> Acum includeți de multe ori pentru a extinde dimensiunea în memorie a acestei structuri XML Ține-o tot așa... ...

Dacă găsiți un echilibru între dimensiunea șirului de entități personalizate și cantitatea de utilizare din corpul documentului, atunci puteți crea un astfel de fișier XML sau șir care, atunci când este extins, va prezice consumul de memorie a serverului. Dacă îl completați cu astfel de întrebări repetitive, atunci va apărea un adevărat atac DOS. Dezavantajul abordării: XML inițial trebuie să fie și el destul de mare, deoarece consumul de memorie depinde de simplul efect al înmulțirii.

Expansiunea recursiva a unei entități

În timp ce extinderea generală necesită utilizarea unui XML inițial mare, extinderea recursivă oferă un factor de mărire mult mai mare. Această metodă se bazează pe seturi de descompunere (rezolvare) exponențială de entități mici, astfel încât acestea să crească semnificativ în dimensiune. În mod destul de logic, această metodă este adesea denumită Bomba XML și Atacul Billion Laughs.


]> Explodează în 3...2...1...

O bombă XML nu necesită XML mare, care uneori poate fi limitat de aplicație. Atacul face ca memoria să fie umplută cu text a cărui dimensiune este de 2^100 de ori dimensiunea valorii originale a entității - . Adevărata BOMBĂ!

Extensie de entitate de la distanță

Ambele atacuri de mai sus folosesc entități definite local în DTD XML. Dar un atacator este capabil să determine entitatea de la distanță dacă analizatorul XML poate face solicitări HTTP externe. După cum am văzut în descrierea XXE (External XML Entity Injection), această capacitate ar trebui să fie dezactivată ca măsură de securitate de bază. Astfel, apărându-ne împotriva XXE, ne apărăm și împotriva acestui tip de atac.


În orice caz: pentru acest atac, parserul XML trebuie să facă cereri HTTP externe pentru a prelua valoarea extinsă a entităților relevante. La rândul lor, ei vor defini independent noi entități externe, cărora analizatorul va trebui să le facă solicitări HTTP suplimentare. Așadar, câteva interogări cu aspect inofensiv vor scăpa rapid de sub control, punând mai multă presiune asupra resurselor disponibile de server, ceea ce poate duce la extinderea recursivă a entităților și poate înrăutăți lucrurile.


]> 3..2..1...&cascada

Codul de mai sus permite și un atac DOS mai subtil: cererile externe trebuie adaptate aplicației locale sau oricărei alte aplicații care partajează resursele serverului. Ca rezultat, sistemul se va ataca singur: încercările de a descompune (rezolva) entități externe folosind un parser XML vor provoca trimiterea multor solicitări către aplicații locale și consumarea multor resurse de server. Acest atac poate fi folosit pentru a amplifica efectul unui atac XXE pentru a executa în continuare un atac DOS.

Protecția extensiei entităților XML

Metodele de apărare sunt aceleași ca și în cazul atacurilor unice XXE. Este necesar să dezactivați extinderea (rezoluția) entităților XML personalizate în fișiere locale, precum și funcții; dezactivați solicitările HTTP externe cu următoarea funcție, care se aplică la nivel global tuturor extensiilor PHP XML bazate pe utilizarea libxml2.


libxml_disable_entity_loader(true);


Cu toate acestea, PHP nu oferă un mijloc evident de dezactivare completă a definiției entităților personalizate cu XML DTD prin DOCTYPE. PHP definește constanta LIBXML_NOENT , există și o proprietate publică DOMDocument::$substituteEntities , dar acestea nu îmbunătățesc situația. Se pare că va trebui să-ți folosești propriile soluții.


libxml2 este inerent intolerant la descompunerea recursiva a entităților, astfel încât jurnalul de erori va fi decorat ca un brad de Crăciun. Prin urmare, nu trebuie să implementăm o protecție specifică împotriva entităților recursive; deși trebuie făcut ceva în cazul în care libxml2 recidivează.


Deci, noua amenințare principală este abordările de forță brută cu bombă XML sau extensia de entitate generală. Aceste atacuri nu necesită apeluri de sistem locale sau de la distanță și nu necesită recursiunea entității. În esență, singurul remediu este eliminarea sau igienizarea XML-ului dacă conține un DOCTYPE. Este mai sigur să ștergem dacă nu trebuie să folosim DOCTYPE și dacă nu l-am primit dintr-o sursă de încredere, adică printr-o conexiune HTTPS verificată. În caz contrar, trebuie să creăm o logică personalizată, deoarece PHP nu ne oferă o opțiune de lucru pentru a dezactiva DTD-urile. Presupunând că puteți apela libxml_disable_entity_loader(TRUE) , atunci următorul cod este sigur, deoarece entitatea nu se va extinde până când nu este accesată valoarea nodului infectat cu expansiune. Și în timpul acestui test, acest lucru nu se va întâmpla.


$dom = document DOMD nou; $dom->loadXML($xml); foreach ($dom->childNodes ca $child) ( dacă ($child->nodeType === XML_DOCUMENT_TYPE_NODE) ​​​​( aruncați nou \InvalidArgumentException ("XML nevalid: a detectat utilizarea DOCTYPE ilegală"); ) )

Desigur, trebuie, de asemenea, să joci în siguranță și să setați libxml_disable_entity_loader la TRUE, astfel încât referințele la entități externe să nu fie rezolvate atunci când XML este încărcat prima dată. Aceasta poate fi singura apărare posibilă în care parserul XML nu depinde de libxml2, cu excepția cazului în care acel parser are un set cuprinzător de opțiuni pentru gestionarea descompunerii entităților.


Dacă intenționați să utilizați SimpleXML, rețineți că puteți importa un obiect DOMDocument validat folosind funcția simplexml_import_dom().

7,4K
În acest articol, voi descrie crearea și trimiterea unui formular AJAX. După aceea, ne putem uita la implementarea animației cu animate.css , a validării datelor cu JavaScript.

La momentul scrierii acestui articol, Bootstrap 3.3.5 este versiunea actuală a cadrului. Pentru acest articol, folosim versiunea Bootstrap implicită (12 coloane). Când finalizați sarcinile din acest articol, asigurați-vă că utilizați cele mai recente fragmente și structura de cod descrise în Documentația bootstrap.

Structura fișierelor și folderelor

Vom crea un director rădăcină și vom adăuga următoarele fișiere și foldere la el:

Formular bootstrap:


Va trebui să includem câteva biblioteci front-end:
  • Bootstrap ;
  • jquery.

Având în vedere aceste biblioteci, structura fișierului va arăta astfel:

Formular bootstrap:

Crearea formei

Deschideți fișierul index.html și copiați următoarea structură de bază în el Formulare de contact AJAX:

Formular de contact folosind Bootstrap 3.3.4 "

Trimite-mi un mesaj

Acesta este șablonul HTML de bază în care vom adăuga conținutul formularului. Am inclus toate fișierele CSS și JavaScript necesare. Rețineți că nu avem nevoie de bootstrap.js pentru acest exemplu special.

Am inclus metaeticheta viewport pentru interogări media în Bootstrap . JavaScript a fost plasat în partea de jos a fișierului, astfel încât codul principal să fie procesat mai întâi.

În eticheta body, am inclus un div cu clasa col-sm-6 col-sm-offset-3 . Aceasta înseamnă că în interiorul și deasupra ferestrei de vizualizare sm (mică) dorim să afișam o coloană lată de 50% ( numărul maxim de coloane 12). Clasa col-sm-offset-3 stabilește marja din stânga la 25%.

Acest lucru creează un aspect care ocupă jumătate din spațiul disponibil și este centrat pe orizontală. După aceea, am inclus h3 și apoi vine baza formularului. Asigurați-vă că dați formularului un ID, astfel încât să puteți atașa ulterior un eveniment de trimitere a formularului AJAX jQuery:

Nu există victorie fără luptă

Acestea sunt toate câmpurile de introducere și butoanele cu care utilizatorul va interacționa. Div-ul inițial cu clasa de rând este sintaxa clasică Bootstrap, care este o grupare orizontală de elemente col. Coloanele din Bootstrap creează umplutură sau spații albe. Îndepărtându-le, vă puteți asigura că sfoara se potrivește uniform în recipient.

Am creat două coloane cu clasa col-sm-6 (50%) pe care le vom folosi pentru a separa partea de sus a formularului. În prima coloană, col-sm-6, am creat o etichetă și câmpuri pentru nume și e-mail. Fiecare conține o etichetă cu un atribut corespunzător pentru, astfel încât eticheta este asociată cu câmpul corespunzător.

Fiecare dintre aceste coloane include un grup de formulare , care grupează etichetele semantic, creând o ușoară umplutură în partea de jos:

Tipografie

Bootstrap permite cursuri pentru H1-H6. Ele vă ajută să stilați elementele inline fără a adăuga câmpuri suplimentare sau a crea blocuri de elemente de formular de contact super AJAX. Am folosit o clasă pentru H4 pentru a modela etichetele și a le face mari.

Clasa de control al formularului este aplicată fiecărui element de intrare, astfel încât să ocupe toată lățimea containerului (lățime 100%). Această clasă adaugă, de asemenea, diverse stiluri care vă permit să creați un element de formular ușor de citit ( dimensiuni mari, margini clare etc.).

După aceste coloane, includem corpul mesajului. Îl împachetăm într-un grup de formulare și aplicăm aceleași stiluri ca pentru etichete și pentru câmpurile de text.

Apel la acțiune

Să creăm un buton de trimitere. Bootstrap conține clase pentru diferite butoane și stările acestora. Am decis să folosim butonul " succes” (btn-succes), care este verde în mod implicit.

De asemenea, trebuie să aplicați clasa de bază btn pentru a reseta setările de bază ale butonului ( cadru, umplutură, alinierea textului, dimensiunea fontului). Am aplicat clasa btn-lg, care creează un buton mare, și apoi clasa pull-right, care înfășoară butonul din stânga.

După buton, am inclus un div cu id-ul #msgSubmit și am aplicat următoarele clase: " h3 text-center ascuns". Clasa h3 ajută la crearea unui titlu mai mare, text-center setează alinierea textului la centru, iar seturile ascunse afișează: niciunul și vizibil: ascuns :

Adăugarea funcției de trimitere a datelor

Am creat un formular Bootstrap jQuery AJAX de bază, dar încă nu face nimic. Următorul nostru pas este să creăm o funcție care acceptă intrarea utilizatorului și o trimite asincron către PHP.

Deschideți fișierul scripts.js și copiați următorul cod în el:

$("#contactForm").submit(function(event)( // anulează transmiterea formularelor event.preventDefault(); submitForm(); ));

Acest Fragment de cod jQuery, care ascultă #contactForm ( după cum s-a afirmat mai înainte). Înainte de această funcție, ne ocupăm de variabila eveniment, care deține acțiunea de a trimite datele din formular pentru funcție.

event.preventDeafult() oprește trimiterea datelor din formular atunci când pagina este reîmprospătată fără a selecta o acțiune în formular. Și la sfârșit, acest cod solicită funcția submitForm(); :

function submitForm()( // Initializeaza o variabila cu continutul formularului var name = $("#name").val(); var email = $("#email").val(); var mesaj = $(" #message ").val(); $.ajax(( tip: "POST", url: "php/form-process.php", date: "name=" + name + "&email=" + email + "&message =" + mesaj, succes: function(text)( if (text == "succes")( formSuccess(); ) ) )); ) function formSuccess()( $("#msgSubmit").removeClass("hidden" );)

Cele trei variabile declanșate captează valorile fiecărui câmp de intrare ale formularului și le transmit unei variabile JavaScript pentru utilizare ulterioară.

noi initiem obiect ajax în interiorul jqueryși setați parametrii pentru postare, adresa URL a fișierului PHP, datele pe care vrem să le trimitem și funcția de apel invers. Datele includ toate cele trei variabile cu id-ul corespunzător. Funcția de apel invers este apelată atunci când obiectul AJAX a primit cu succes informații din scriptul PHP. Funcția preia textul returnat și verifică dacă este egal cu șirul " succes". Dacă da, atunci funcția finală formSuccess este rulată.

Îndepărtează clasa ascunsă din #msgSubmit DIV pe care l-am aplicat mai devreme, afișând astfel textul.

Conectarea la funcția PHP Mail

Acum trebuie să scriem un script care va primi date din formularul AJAX și să trimitem conținutul prin funcția PHP Mail. Deschideți fișierul process.php și adăugați următorul cod la acesta:

Trebuie să stocăm variabilele pe care vrem să le folosim. Trei variabile de intrare pot fi preluate din funcția de e-mail și pot fi primite aceleași nume în PHP. Variabila $EmailTo este o adresă de e-mail care poate fi setată în script. $Subject este un șir care descrie subiectul e-mailului.

Corpul literei este creat în mod arbitrar cu adăugarea a trei variabile create. Mai întâi, setăm textul descrierii, de exemplu, „ Nume:", apoi vine variabila și apoi o nouă linie (/n) . Repetăm ​​aceiași pași, legând toate datele la variabila $body.

Pentru a trimite un e-mail, îl atașăm la funcția de e-mail. Atribuind o valoare variabilei $success, setăm adresa de e-mail la care va fi trimis e-mailul, subiectul e-mailului, corpul și adresa de e-mail a expeditorului.

Pentru a începe procesul de trimitere a unui e-mail, trebuie să îl apelați într-o declarație if. Astfel puteți verifica dacă datele formularului au fost trimise cu succes sau nu. Dacă funcția Mail revine „ Adevărat”, scriptul returnează „ succes”, dacă funcția aruncă o eroare, returnează „ invalid”.

Acest rezultat va fi returnat obiectului AJAX și procesat pe partea clientului. Avantajul AJAX este că totul se face asincron pe partea clientului. Acest lucru permite utilizatorului să continue să interacționeze cu site-ul în timp ce trimite datele formularului AJAX:

Să strălucim

Acum ne vom concentra pe furnizarea de feedback utilizatorilor prin diverse funcții suplimentare care pot fi activate. În special, vom analiza feedback-ul din formular utilizând gestionarea erorilor, atât pe partea client, cât și pe partea serverului.

De asemenea, folosim câteva instrumente pentru a valida formularul:

  • Animate.css: ;
  • Validator Bootstrap.

Adăugați-le la proiect așa cum am făcut mai devreme cu Bootstrap și JQuery. Aceste instrumente vor ajuta la furnizarea de feedback utilizatorului după ce acesta a trimis datele.

Structura proiectului ar trebui acum să arate astfel:

Validarea formularului

Să începem prin a configura un validator după introducerea datelor din formularul de contact PHP AJAX. Accesați fișierul scripts.js și editați prima bucată de cod care apelează funcția SubmitForm() după ce datele formularului sunt trimise.
Trebuie schimbat astfel:

$("#contactForm").validator().on("trimite", funcția (eveniment) ( if (event.isDefaultPrevented()) ( // gestionează eroarea formularului... ) else ( // totul este bine! eveniment .preventDefault(); submitForm(); ) ));

Acest nou fragment de cod verifică dacă Bootstrap Validator a găsit probleme și a oprit rularea codului. Dacă nu, continuăm cu acțiunile în modul standard. Încă trebuie să excludem acțiunea implicită ( reîncărcarea paginii fără a completa formularul) din scriptul de trimitere a datelor din formular.

Acum, dacă facem clic pe butonul de trimitere al datelor din formular fără a completa toate câmpurile, cele goale vor fi evidențiate cu roșu:


În procesul de adăugare a validării, am dezactivat validarea HTML5 nativă. Puteți adăuga context suplimentar la validare prin includerea mesajelor de eroare. Validatorul Bootstrap are o caracteristică la îndemână care vă permite să afișați mesaje de eroare pentru fiecare câmp. Pentru a le adăuga, trebuie să completați marcajul HTML.

În interiorul fiecărui grup de formulare, sub câmpul de introducere a datelor, plasați următorul cod HTML:

Ca exemplu, mai jos este un div suplimentar adăugat la câmpurile de nume și e-mail:

Acum, când retrimiteți datele formularului AJAX jQuery, va fi afișat un mesaj de eroare dacă câmpurile formularului nu au fost completate: „ Vă rugăm să completați acest câmp.". Prin adăugarea unui atribut de date pentru datele de intrare numit „ eroare de date”, puteți include un mesaj de eroare personalizat.

De exemplu:

Adăugarea de animație de feedback

Am adăugat o funcționalitate pentru a indica câmpurile de formular goale. Dar ar fi bine să adăugați o animație suplimentară la formular și câteva mesaje pentru a informa utilizatorul ce se întâmplă. În prezent, la trimiterea cu succes a datelor din formular, mesajul „ Mesaj trimis!„Dar ce zici de greșeli?

Pentru a utiliza codul existent, vom modifica mesajul de succes al transmiterii datelor existente. În primul rând, eliminați textul " Mesaj trimis!' din marcajul HTML și lăsați un div gol:

Acum trebuie să creăm o nouă funcție pentru a procesa starea mesajului. Adăugați această funcție în partea de jos a fișierului dvs. scripts.js:

function submitMSG(valid, msg)( var msgClasses; if(valid)( msgClasses = "h3 text-center tada animated text-success"; ) else ( msgClasses = "h3 text-center text-danger"; ) $("# msgSubmit").removeClass().addClass(msgClasses).text(msg); )

Această funcție are două argumente. valid va fi o variabilă booleană: dacă valoarea sa este adevărată, va fi afișat un mesaj care indică faptul că datele au fost trimise cu succes. Dacă este fals, va fi afișat un mesaj de eroare. msg este mesajul pe care îl vom afișa pe ecran în blocul div.

Această funcție verifică dacă avem de-a face cu un mesaj de trimitere de date cu succes sau cu un mesaj de eroare. Acest lucru se face prin verificarea valorii variabilei valide. În orice caz, setează o variabilă cu clasele CSS corespunzătoare ( trebuie să reactivăm h3 și text-center, deoarece le vom elimina).

Notă: folosim câteva clase animate.css pentru clasa de mesaje de succes. După trimiterea cu succes a datelor din formularul de contact AJAX JQuery, se va reda animația tada.

În cele din urmă, funcția elimină toate clasele din #msgSubmit ( pentru a evita suprapunerea claselor) și apoi setează clasele de prioritate și adaugă textul mesajului la div.

În inițializarea validatorului de la începutul acestei secțiuni, actualizăm codul pentru a adăuga următorul apel de funcție în instrucțiunea if când se evaluează la adevărat:

submitMSG(false, „Ați completat corect formularul?”);

Acum, dacă nu ați completat toate câmpurile, va fi afișat un mesaj de eroare „ Ai completat corect formularul?»

Ultimul pas pentru această nouă funcție submitMSG este să o apelați atunci când datele din formular sunt trimise cu succes. Actualizați funcția formSuccess() după cum urmează:

$("#contactForm").reset(); submitMSG(true, „Mesajul trimis!”)

Dorim să resetam formularul și să ștergem valorile atunci când apelăm funcția submitMSG ca mai sus cu un mesaj de succes. Acum, după trimiterea cu succes a datelor din formular, ar trebui să fie afișat un mesaj corespunzător cu animația animate.css tada :

hai să-l scuturăm

Să adăugăm o animație de eroare întregului formular, animația generică „agitare” ar trebui să facă treaba!

Creați unul nou imediat după funcția formSuccess() și numiți-o formError() :

function formError()( $("#contactForm").removeClass().addClass("shake animated").one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend", function()( $(this).removeClass(); )) ;)

Această funcție folosește abordarea descrisă pe pagina demo animate.css, care vă permite să adăugați o animație unui element și apoi să o apelați din nou.

Animația CSS are o particularitate urâtă: nu poate fi reluată chiar dacă eliminați și adăugați din nou clasa. Această caracteristică ajută la resetarea claselor de final de animație, permițându-vă să le adăugați din nou. Când utilizatorul face clic pe butonul Trimite fără a completa toate câmpurile formularului de contact AJAX, redăm o animație de agitare. Și dacă nu completează din nou toate câmpurile, trebuie să redai această animație.

Puteți apela această funcție formError() deasupra funcției submitMSG() pe care am creat-o pentru a raporta eroarea. De exemplu, așa:

formError(); submitMSG(false, „Ați completat corect formularul?”);

Acum, când utilizatorul încearcă să trimită datele din formular fără a completa toate câmpurile, acesta se va zgudui astfel încât să înțeleagă că ceva nu este în regulă.

Mai multă validare

Validarea la nivelul clientului este bună, dar orice utilizator o poate dezactiva și trimite formularul cu câmpuri goale prin editarea codului în browser. Trebuie să creați un serviciu de validare pe partea serverului.

Trebuie să deschidem fișierul process.php și să facem modificările necesare pentru a ne asigura că toate câmpurile sunt completate. Vom crea o variabilă $errorMSG pentru a capta mesajele de eroare, apoi vom activa o verificare suplimentară $_POST:

Acest cod PHP verifică dacă există câmpuri de formular AJAX goale înainte de a-și seta datele ca variabile adecvate ( înlocuiește variabilele existente setate în codul de la $_POST). Dacă câmpurile sunt goale, setăm mesajul general să fie trimis înapoi clientului.

Ca răspuns la apelul AJAX original, trebuie să trimitem un mesaj de eroare care să fie afișat în browser. Pentru a face acest lucru, editați instrucțiunea if pe care am creat-o mai devreme în partea de jos a codului PHP:

Prin instrucțiunea if, verificăm dacă variabila $errorMSG este goală ("") , precum și starea funcției Mail încorporate pe care am folosit-o pentru variabila $success. În clauza else, am inclus o verificare suplimentară pentru a vedea dacă eroarea este rezultatul unui eșec $success. Dacă da, trimiteți înapoi mesajul „ Ceva n-a mers bine:„. În caz contrar, tipărim mesajul care a fost compilat când am verificat câmpurile goale.

Iar ultimul pas este să acceptați un mesaj nou în AJAX și să îl afișați în formular. Trebuie să actualizăm obiectul AJAX din fișierul scripts.js astfel:

$.ajax(( tip: "POST", url: "php/form-process.php", date: "name=" + nume + "&email=" + email + "&message=" + mesaj, succes: function( text)( if (text == „succes”)( formSuccess(); ) else (formError(); submitMSG(false,text); ) ) ));

Tocmai am actualizat condiția else, care verifică pentru text == succes . În else, apelăm funcția formError(), care aplică animația shake, și solicităm funcției submitMSG() textul returnat de PHP.

Concluzie

Verificați Github pentru a vedea codul complet. Acum Formular de feedback PHP AJAX oferă utilizatorului informații despre care dintre câmpurile nu a completat. Afișăm mesaje contextuale pe baza stării și a mesajului returnat din PHP. Și a implementat, de asemenea, un nivel suplimentar de validare pe server pentru acei utilizatori care încearcă să ocolească validarea front-end.

Sper că v-a plăcut acest articol. Vă rugăm să lăsați întrebările și feedback-ul dvs. în comentarii.

Această publicație este o traducere a articolului „ Crearea unui formular de contact Bootstrap folosind PHP și AJAX» pregătit de o echipă de proiect prietenoasă

Acesta este un mod accesibil și sigur de a plăti pentru bunuri și servicii prin Internet. Adăugați procesorul acestui sistem în magazinul dvs. online și acceptați plăți fără întârziere.

Protocolul actualizat Yandex.Money 3.0 permite utilizarea diferitelor tipuri de plată:

  • De fapt Bani Yandex;
  • carduri bancare;
  • Plăți prin terminale;
  • Plăți mobile.
În plus, procedura de conectare a magazinelor create pe platformă 1C-Bitrix: managementul site-ului, la Yandex.Banii sunt foarte simplificați. Trebuie să lăsați o solicitare pe site-ul Yandex.Money (indicați în comentariu pe care aveți un site web cu versiunea de protocol 3.0.) și completați un chestionar simplificat (format din doar 3 câmpuri).

Pentru a conecta noul protocol Yandex.Money într-un magazin online de pe platforma 1C-Bitrix, trebuie să creați un nou sistem de plată și să selectați un procesor

Verificați dacă site-ul dvs. răspunde cu protocolul https. Aceasta este o condiție prealabilă pentru acceptarea plăților conform protocolului Yandex.Money 3.0.

Puteți utiliza un certificat SSL autosemnat sau mașina noastră virtuală, unde totul este deja configurat.

Apoi, indicați ID stocare în CPP, Numărul vitrinei la CPP, pe care trebuie să îl primiți de la Yandex la încheierea contractului și Parola magazin (shopPassword) din profilul magazinului pentru Yandex.

Pentru fiecare tip de rambursare, va trebui să vă creați propriul operator și să selectați tipul de plată necesar.

Pentru a testa plata, trebuie să puneți valoarea „Y” în câmp Modul de testare. Când trimiteți o aplicație pentru a conecta protocolul Yandex.Money 3.0, veți primi un link special, folosindu-vă să vă completați soldul portofelului pentru test cu 1000 de ruble.

În setările modulului Magazin online, puteți redefini căile către pagini cu un mesaj despre plata reușită sau o eroare.

Tot. Setarea a fost finalizată. Vă rugăm să utilizați

Clienții care au conectat versiunea anterioară a Yandex.Money (1.6) nu trebuie să facă upgrade la versiunea 3.0. Acestea. Ambele versiuni sunt acceptate atât de Yandex.Money, cât și de 1C-Bitrix: Site Management. DAR versiunea 1.6 nu adaugă posibilitatea de a utiliza alte plăți decât Yandex.Money. Noii clienți ai acestui sistem de plată sunt conectați prin protocolul 3.0.

La livrarea produsului 1C-Bitrix: Managementul site-ului Yandex.Money handler (3.0) va fi lansat în versiunea 14.0.0 a modulului Magazin online (vânzare). Înainte de lansarea acestei actualizări (presupunem că va fi lansată în alfa la sfârșitul lunii), gestionarea poate fi solicitată prin intermediul Asistenței Tehnice.

Pe lângă funcționalitatea de bază, ar trebui adăugate următoarele caracteristici:
  • Utilizatorul poate folosi următoarele etichete HTML în mesaje:
  • Trebuie să existe o verificare a etichetelor de închidere, codul trebuie să fie XHTML valid
  • Cartea de oaspeti. JavaScript și AJAX

    Pe lângă funcționalitatea de bază, ar trebui adăugate următoarele caracteristici:
    • Validarea datelor de intrare pe server și pe partea clientului
    • Funcție de previzualizare și adăugare a unui mesaj, fără a reîncărca pagina
    • Pentru etichetele HTML, faceți un panou cu butoane (,,,,)
    • Adăugarea de efecte vizuale este, de asemenea, binevenită.
  • Cerințe

    Sistemul ar trebui să funcționeze corect pe sistemul de operare Linux cu următoarea configurație:

    • PHP 5.1+
    • MySQL 4.1+
    • Apache 2.2+
    Este acceptabilă utilizarea următoarelor biblioteci:
    • PHP Zend Framework sau PEAR
    • JS jQuery sau Prototype

    P.S. Imaginea arată un motor Stirling, wikipedia dă adesea de gândit...

    upd: pe blogul meu a aparut un comentariu foarte corect:

    oameni, se pare că nu înțelegeți pentru cine este concepută această sarcină. O persoană cu experiență în mod NATURAL nu o va face din două motive: a) nu vrea să piardă timpul și b) nu i se va da.

    Dar realitatea este că aceasta este adesea, în general, prima sarcină mai mult sau mai puțin voluminoasă a solicitantului pentru postul de dezvoltator junior php.

    Prin urmare, 80 de ore sunt acordate nu pentru a face pur și simplu această sarcină, ci pentru a aduce realitatea (cunoștințele sale) în conformitate cu bifele din CV-ul său vizavi de php, html, css, js, ajax, mysql.

    Ca rezultat, obținem un anumit indicator integral atât al aptitudinilor, cât și al capacității de învățare și al capacității de a căuta pe Google.

    De fapt, face față acestei sarcini.

    Iar candidații care au ceva de arătat merg în mod firesc direct la proiecte.


    Etichete: Adăugați etichete

  • În era web-ului modern, majoritatea site-urilor devin din ce în ce mai interactive. Dacă mai devreme, pentru a primi date actualizate, trebuia să actualizăm întreaga pagină, acum au apărut tehnologii care permit ca pagina să nu fie încărcată complet, ci doar o parte separată a acesteia. La rândul său, acest lucru oferă confort atât utilizatorilor, cât și proprietarilor de server, deoarece pentru utilizator, încărcarea paginii va fi mai rapidă, deoarece este încărcată doar o parte separată a paginii, iar serverul nu trebuie să genereze pagina de fiecare dată și să o dea. către utilizator. Aceste caracteristici sunt ușor de implementat folosind php și ajax.

    Astăzi vom analiza un mic exemplu pentru o mai bună înțelegere a modului în care funcționează conceptul. AJAX. Uneori este dificil pentru începători să înțeleagă modul în care php și ajax interacționează între ele, mulți oameni caută exemple despre cum să valideze formularele din mers fără a reîncărca întreaga pagină. Vă voi arăta pe scurt cum se face acest lucru, astfel încât să puteți înțelege elementele de bază și principiile care vă vor permite să stăpâniți rapid alte instrumente în viitor și să vă scrieți propriile scripturi.

    Să venim cu o mică sarcină pentru noi înșine, vom verifica prezența unei adrese de e-mail în baza de date fără a reîncărca pagina folosind php și ajax. Un astfel de exemplu va demonstra bine cum putem interacționa cu serverul fără a reîncărca pagina în browser și, de asemenea, acest lucru este adesea folosit în diferite tipuri de validări ale formularelor de utilizator. Să creăm 3 fișiere în directorul rădăcină numit index.php , email.php , validate.js .

    Crearea paginii

    Să creăm o pagină simplă cu un singur formular care conține un singur câmp pentru introducerea e-mailului.
    Sintaxa fișierului index.php

    Tutorial AJAX

    Cel mai simplu mod de a lucra cu AJAX este de a conecta cadrul jQuery care este exact ceea ce am făcut. jQuery ne oferă o sintaxă ușor de înțeles și de funcționare pentru trimitere AJAX cereri, de ce să nu profitați de asta?

    Crearea unui script js

    sintaxa fișierului validate.js

    $(document).ready(function()( var email = ""; $("#email").keyup(function()( var value = $(this).val(); $.ajax(( tip: "POST", url:"email.php", date:"email="+valoare, succes:function(msg)( if(msg == "valid")( $("#message").html(" Acest e-mail poate fi folosit.Această adresă de e-mail este deja luată."); ) ) )); )); $("#submit").click(function()( if(email == "")( alert("Vă rugăm, puneți date în toate e-mailurile"); )else( $.ajax(( tip: "POST", url:"email.php", date:"add_email="+email, succes:function(msg)( $("#message").html(msg); ) ) ); ) )); ));

    handler php

    Acest script va primi POST cerere de la client, o procesează și returnează rezultatul. AJAX citește rezultatul și ia o decizie pe baza acestuia.
    Sintaxa fișierului email.php

    $connection = mysqli_connect("localhost","email","email","email"); if(isset($_POST["email"]) && $_POST["email"] != "")( $email = $_POST["email"]; $email = mysqli_real_escape_string($conexiune,$email); dacă (!filter_var($email, FILTER_VALIDATE_EMAIL))( echo "invalid"; )else( $sql = "SELECT ID FROM email WHERE email="$email""; $rezultat = mysqli_query($conexiune,$sql); if( mysqli_num_rows($rezultat) == 1)( echo "invalid"; )else( echo "valid"; ) ) ) if(isset($_POST["add_email"]) && $_POST["add_email"] != "" )( $email = mysqli_real_escape_string($connection,$_POST["add_email"]); $sql = "INSERT INTO email(email) VALUES("$email")"; if(mysqli_query($connection,$sql))( ecou succes"; )else( ecou " eroare"; } }

    În scriptul nostru php, cel mai comun cod care procesează cererea de postare și imprimă un anumit text pe pagină. Ca urmare AJAX trimite o solicitare unui script php, scriptul o procesează și returnează rezultatul, AJAX citește rezultatul și schimbă pagina în timp real.

    AJAX transmite cererea POST către script cu această bucată de cod:

    $.ajax(( tip:"POST", url:"email.php", date:"email="+valoare, succes:funcție(msg)( if(msg == "valid")( $("#mesaj) ").html(" Acest e-mail poate fi folosit."); e-mail = valoare; )else( $("#mesaj").html(" Această adresă de e-mail este deja luată."); } } });

    tip - Tip cerere, POST sau GET. În cazul nostru POST;
    url - adresa script-ului la care este trimisă cererea;
    date - date care sunt transmise în cerere;
    succes - ce trebuie făcut ca urmare a unei cereri reușite. În cazul nostru, o funcție este numită;

    În scriptul propriu-zis, verificarea prezenței e-mailului în baza de date se realizează de fiecare dată când se introduce un caracter în câmpul de e-mail. În script, secțiunea $("#email").keyup(function()()); este responsabilă pentru procesarea intrării. , care verifică dacă apăsați tasta în câmpul cu id = „email” .
    După cum puteți vedea, codul este destul de simplu și nu necesită abilități deosebit de mari pentru a înțelege, totul este legat de gestionarea evenimentelor keyup () - apăsând o tastă, faceți clic pe () - faceți clic cu mouse-ul pe un element. Urmat de AJAX cerere și răspuns din script. Astfel, folosind php și ajax, puteți obține posibilități aproape nelimitate de a crea pagini interactive.
    Acest cod nu se pretinde a fi de înaltă calitate, dar dacă îl dezvoltați, adăugați validările corecte la nivel de client și server, introduceți css, apoi îl puteți utiliza în proiectele dvs.
    Dacă aveți întrebări, nu ezitați să scrieți comentarii.
    Vă doresc o zi bună și ne vedem curând 🙂