Înțelegerea integrității subresursei
Publicat: 2022-03-10 Dacă ați folosit vreodată o versiune găzduită de CDN a unei biblioteci JavaScript, este posibil să fi observat un atribut de integrity
cu aspect ciudat pe eticheta de script. Acest atribut conține nedorit alfanumeric aparent nesfârșit pe care ați putea fi tentat să le eliminați în căutarea unui cod mai curat.
Toate aceste nedorite sunt de fapt o caracteristică de securitate cu adevărat utilă numită Subresource Integrity (SRI) care vă poate ajuta să vă apărați site-ul împotriva anumitor tipuri de hack-uri și compromisuri. În acest articol, vom arunca o privire la ce este SRI, cum vă poate ajuta să vă protejați și cum puteți începe să îl utilizați în propriile proiecte, nu doar pentru fișierele găzduite pe CDN-uri.
Un pic de istorie
În vremurile când JavaScript era vărul mai sărac cu HTML și CSS, nu trebuia să ne gândim prea mult la modul în care scripturile noastre puteau fi folosite ca vector de atac pentru site-urile noastre web. Cele mai multe site-uri au fost toate găzduite pe un singur server fizic undeva pe propria infrastructură de găzduire și acesta a fost serverul pe care ne-am gândit să-l apărăm când a venit vorba de cele mai bune practici de securitate.
Pe măsură ce browserele au devenit mai capabile și conexiunile la rețea s-au îngroșat, am început să folosim tot mai mult JavaScript și, în cele din urmă, au început să apară biblioteci JavaScript reutilizabile. În acele zile de început, biblioteci precum script.aculo.us, Prototype și, în cele din urmă, jQuery au început să câștige adoptarea în rândul dezvoltatorilor care căutau să adauge mai multă interactivitate în paginile lor.
Odată cu aceste biblioteci adăugate și plugin-uri ulterioare, s-a adăugat greutatea paginii și în scurt timp am început să ne gândim serios la performanța front-end. Resurse precum Content Delivery Networks (CDN), care fuseseră anterior rezerva unor corporații gigantice, deveneau obișnuite pentru oamenii de zi cu zi care construiau site-uri web captivante.
Pe parcurs, o scânteie strălucitoare a observat că toate site-urile își solicitau propriile copii ale bibliotecilor comune - lucruri precum cel mai recent jQuery - și dacă ar exista o versiune CDN comună a acelor biblioteci care ar putea fi folosită de fiecare site, atunci utilizatorul ar" nu trebuie să continui să descarci același fișier. Aceștia ar primi lovitura ca primul site să folosească fișierul, dar apoi ar fi stat în memoria cache a browserului local și descărcări ar putea fi omise pentru fiecare site ulterior. Geniu!
Acesta este motivul pentru care veți vedea linkuri CDN pentru bibliotecile dvs. preferate folosind URL-uri precum jsdelivr.com
- folosesc un CDN comun pentru a găzdui fișierele, astfel încât utilizatorii lor să vadă beneficiile de performanță.
Ce ar putea merge prost?
Acesta rămâne un mod bun, practic de a lucra, dar introduce un potențial vector de atac. Să ne imaginăm că este 2012 și toată lumea folosește noul jQuery 1.8. Înapoi cu modul tradițional de a face lucrurile, fiecare ar avea propriul fișier jQuery 1.8 găzduit ca parte a propriului site pe propriul server.
Dacă ai fi un fel de actor rău – cum ar fi un fel de Hamburglar bazat pe jQuery – și ai fi găsit o modalitate furtună de a pirata biblioteca pentru propriile câștiguri malefice, ar trebui să țintiți fiecare site web individual și să compromiteți serverele lor pentru a avea orice impact. Asta înseamnă mult efort.
Dar nu așa stau lucrurile acum, deoarece toată lumea folosește jQuery încărcat de la un CDN comun. Și când spun toată lumea, nu mă refer la sute de pagini web. Mă refer la milioane de pagini web. Dintr-o dată acel fișier a devenit o țintă foarte atractivă pentru hacker-ul nostru dubios. Dacă pot compromite acel fișier, pot avea codul care rulează foarte rapid în milioane de pagini web de pe tot globul.
Nu contează care este acel cod. Ar putea fi o farsă pentru a deforma paginile, ar putea fi cod pentru a vă fura parolele, ar putea fi cod pentru a extrage criptomonede sau ar putea fi urmăritori furtivi care să vă urmărească pe web și să-și facă un profil de marketing. Important este că fișierul inocent pe care dezvoltatorul l-a adăugat la o pagină a fost schimbat și acum aveți niște JavaScript rău care rulează ca parte a site-ului dvs. Asta e o mare problemă.
Introduceți Integritatea subresursei
În loc să renunțe la ceasuri și să renunțe la o modalitate utilă de utilizare a codului, SRI este o soluție care adaugă un nivel simplu de securitate. Ceea ce face SRI și atributul de integrity
este să vă asigurați că fișierul pe care l-ați conectat la o pagină nu se modifică niciodată. Și dacă se schimbă, atunci browserul îl va respinge.
Verificarea că codul nu sa schimbat este o problemă foarte veche în informatică și, din fericire, are câteva soluții foarte bine stabilite. SRI face o treabă bună adoptând cel mai simplu – hashingul fișierelor.
File hashing este procesul de preluare a unui fișier și de rulare printr-un algoritm care îl reduce la o reprezentare scurtă de șir, cunoscută sub numele de hash sau checksum. Fără a intra în buruieni, procesul este fie repetabil, fie reversibil, atât de mult încât, dacă ați oferi altcuiva un fișier împreună cu hash-ul, ar putea rula același algoritm pentru a verifica dacă cele două se potrivesc. Dacă fișierul se modifică sau hash-ul se modifică, atunci nu mai există o potrivire și știți că ceva nu este în regulă și ar trebui să nu aveți încredere în fișier.
Când utilizați SRI, pagina dvs. web deține hash-ul, iar serverul (CDN sau oriunde) deține fișierul. Browserul descarcă fișierul, apoi calculează rapid pentru a se asigura că se potrivește cu hash-ul din atributul de integrity
. Dacă se potrivește, fișierul este folosit, iar dacă nu este blocat.
Încercând
Dacă mă duc astăzi la getbootstrap.com
pentru a obține un link CDN către o versiune de Bootstrap, mi se dă o etichetă care arată astfel:
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
Puteți vedea că atributul src
este așa cum ne-am obișnuit, iar atributul de integrity
deține ceea ce știm acum a fi un hash.
Hașul este de fapt în două părți. Primul este un prefix pentru a declara ce algoritm de hashing să folosească. În acest caz, este sha384
. Acesta este urmat de o liniuță și apoi de hash-ul în sine, codificat cu base64
.
Este posibil să fiți familiarizat cu base64
ca modalitate de a codifica fișiere inline, cum ar fi imagini, în pagini. Nu este un proces criptografic - este doar o modalitate rapidă și convenabilă de a codifica datele potențial dezordonate într-un mod care se traduce perfect în ASCII. Acesta este motivul pentru care este folosit foarte mult pe web.
Văzând acest lucru, browserul va descărca bootstrap.min.js
. Înainte de a-l executa, va decoda base64
hash-ul și apoi va folosi algoritmul de hash sha384
pentru a confirma că hash-ul se potrivește cu fișierul pe care tocmai l-a descărcat. Dacă se potrivește, fișierul este executat.
Pot testa acest lucru punând acea etichetă într-o pagină și apoi trecând la fila Rețea din instrumentele browserului meu pentru a vedea că fișierul a fost încărcat.
Pot vedea că bootstrap.min.js
(și, de asemenea, fișierul jQuery de care are nevoie) s-au încărcat cu succes.
Să vedem ce s-ar întâmpla dacă actualizez hash-ul pentru a fi ceva despre care știu că este incorect.
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-SmashingMagazineIsCoolForCats" crossorigin="anonymous"></script>
După cum puteți vedea, hash-ul specificat în pagina mea nu se mai potrivește cu fișierul, așa că fișierul este blocat.
Utilizarea SRI în propriile proiecte
A avea această capacitate pentru bibliotecile pe un CDN este grozav, iar dacă vedeți opțiunea de a utiliza un fișier încorporat cu un atribut de integrity
, atunci cu siguranță ar trebui să preferați acea opțiune. Dar nu se limitează la proiecte mari pe CDN-uri, puteți folosi acest lucru singur pentru propriile site-uri.
Nu este deloc exagerat să-ți imaginezi un scenariu în care un hacker reușește să obțină acces la doar câteva fișiere de pe site-ul tău. Cred că cei mai mulți dintre noi am văzut un client, un coleg sau un prieten care a avut la un moment dat un site WordPress compromis cu o mulțime de vechituri urâte despre care nici măcar nu și-au dat seama că este acolo.
SRI vă poate proteja și de acest lucru. Dacă generați hash-uri de integritate pentru propriile fișiere, atunci puteți solicita site-ului dvs. să respingă orice modificare, așa cum ar face pentru un fișier găzduit de la distanță.
Generarea hashurilor
Puteți, așa cum v-ați aștepta, să rulați câteva comenzi la terminalul computerului dvs. pentru a genera un hash pentru un fișier. Acest exemplu despre cum să faceți acest lucru vine de la pagina MDN Subresource Integrity:
cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A
Aceasta înseamnă obținerea conținutului FILENAME.js
și transmiterea acestuia ca intrare către openssl
pentru a crea un digest folosind sha384
, care este apoi transmis ca intrare într-o altă comandă openssl
pentru a codifica rezultatul în base64
. Nu numai că este complicat și obscur, dar nici nu este genul de lucru pe care doriți să îl faceți manual de fiecare dată când fișierul JavaScript se schimbă.
Mai util, veți dori să integrați acest lucru într-un fel în procesul de construire al site-ului dvs. și, după cum v-ați imagina, există o mulțime de opțiuni gata făcute acolo. Implementarea exactă va varia considerabil în funcție de proiectul dvs., dar iată câteva elemente de bază.
Dacă utilizați Gulp pentru a vă construi site-urile, există gulp-sri care va scoate un fișier JSON cu o listă a fișierelor dvs. și hashurile acestora. Apoi, puteți utiliza acest lucru pe site-ul dvs. De exemplu, pentru un site redat dinamic, puteți crea un plugin de șablon pentru a citi fișierul respectiv și pentru a adăuga hash-uri la șabloane, acolo unde este necesar.
Dacă încă sunteți cu Gulp, dar aveți un site static (sau un site generat static), puteți utiliza gulp-sri-hash care va rula de fapt prin paginile dvs. HTML și va modifica paginile pentru a adăuga hashuri acolo unde este necesar, ceea ce este foarte util.
Dacă utilizați Webpack, există o pagină web-subresurse-integritate care, în adevăratul stil Webpack, este mai complex decât s-ar aștepta orice om, dar pare să funcționeze.
Pentru cei care folosesc motorul de șabloane Handlebars, se pare că există opțiuni disponibile pentru dvs., iar dacă procesul dvs. de construire este doar JavaScript de bază, există și soluții simple acolo.
Dacă utilizați un CMS precum WordPress, am găsit un plugin care pare să fie ușor, deși nu l-am încercat eu însumi. Căutarea pe Google pentru propria platformă preferată cu SRI sau Sub Resource Integrity vă va îndruma probabil în direcția cea bună.
În esență, doriți să vă conectați hashing-ul după ce fișierele JavaScript au fost minimizate și apoi să faceți acel hash disponibil într-un fel pentru orice parte a sistemului dvs. care scoate etichetele <script>
. Una dintre minunile platformei web este că este atât de diversă din punct de vedere tehnic, dar asta, din păcate, mă lasă în imposibilitatea de a vă oferi instrucțiuni bune de implementare!
Alte lucruri de remarcat
În acest articol, am vorbit mult despre fișierele JavaScript, deoarece aici este cel mai logic să vă apărați împotriva atacurilor de hacking. SRI funcționează și cu CSS și, deci, îl puteți utiliza exact în același mod acolo. Riscul pentru CSS rău intenționat este mult mai mic, dar potențialul de a deforma un site încă există și cine știe ce erori de browser ar putea duce, de asemenea, la CSS-ul să vă expună site-ul unui hacker din neatenție. Deci, funcționează și folosind SRI acolo.
Un alt lucru interesant pe care îl poți face este să folosești o Politică de securitate a conținutului pentru a specifica că orice script (sau stiluri) de pe pagina ta trebuie să folosească SRI și, desigur, că SRI trebuie să valideze.
Content-Security-Policy: require-sri-for script;
Aceasta este o modalitate de a vă asigura că SRI este întotdeauna utilizat, ceea ce ar putea fi util pe site-urile la care lucrează mai mulți membri ai echipei care ar putea sau nu să fie pe deplin la curent cu cum să facă lucrurile. Din nou, un loc bun pentru a citi mai multe despre acest lucru este documentele MDN întotdeauna grozave pentru Subresource Integrity.
Ultimul lucru despre care merită să vorbim este suportul pentru browser pentru SRI. Suportul în browserele moderne este larg, cu excepția principală fiind Internet Explorer. Cu toate acestea, datorită modului în care a fost implementată compatibil cu versiunea inversă, specificația este sigură de utilizat imediat. Browserele care înțeleg atributul de integrity
vor folosi hash și vor verifica integritatea, iar browserele mai vechi vor continua așa cum au făcut întotdeauna și vor continua să funcționeze. Desigur, nu veți primi protecție suplimentară în acele browsere mai vechi, dar veți primi în browserele care oferă suport.
Concluzie
Am văzut nu numai ce fac acele hashuri ciudate din atributele de integrity
, ci și cum le putem folosi pentru a ne apăra împotriva anumitor tipuri de atacuri pe site-ul nostru. Desigur, nu există niciun glonț de argint care să ne apere site-urile împotriva oricărui tip de exploatare, dar Subresource Integrity este un instrument cu adevărat util în lanț.
Exploatarea unui defect de securitate înseamnă adesea atragerea mai multor bucăți mici de aliniat. Dacă A este pe loc și poți face ca B să se întâmple, atunci o eroare în C face posibilă D. Caracteristicile browserului, cum ar fi SRI, ne oferă o modalitate bună de a lega lucrurile doar puțin mai mult și de a rupe acest lanț și de a împiedica un hacker să obțină ceea ce își dorește. În plus, dacă îl puteți integra în procesul de construire sau CMS, este ceva pe care ar trebui să îl puteți configura o dată și apoi să uitați și nu vă va cauza neplăceri de zi cu zi.
Ca atare, aș recomanda cu adevărat să aruncați o privire serioasă asupra Subresource Integrity și să o implementați pe site-urile dvs. dacă puteți.