Avastage turvalist päritoluülest suhtlust PostMessage API abil. Õppige tundma selle võimekust, turvariske ja parimaid praktikaid veebirakenduste haavatavuste leevendamiseks.
Päritoluülene suhtlus: Turvamustrid PostMessage API abil
Tänapäeva veebis peavad rakendused sageli suhtlema eri päritoluga ressurssidega. Sama päritolu poliitika (Same-Origin Policy, SOP) on oluline turvamehhanism, mis piirab skriptide juurdepääsu teist päritolu ressurssidele. Siiski on olemas legitiimseid stsenaariume, kus päritoluülene suhtlus on vajalik. postMessage API pakub selle saavutamiseks kontrollitud mehhanismi, kuid on ülioluline mõista selle potentsiaalseid turvariske ja rakendada asjakohaseid turvamustreid.
Sama päritolu poliitika (SOP) mõistmine
Sama päritolu poliitika on veebibrauserite fundamentaalne turvakontseptsioon. See piirab veebilehtedel päringute tegemist domeenile, mis erineb sellest, mis veebilehe serveeris. Päritolu on defineeritud skeemi (protokolli), hosti (domeeni) ja pordi abil. Kui ükskõik milline neist erineb, loetakse päritolud erinevaks. Näiteks:
https://example.comhttps://www.example.comhttp://example.comhttps://example.com:8080
Need on kõik erinevad päritolud ja SOP piirab otsest skriptide juurdepääsu nende vahel.
PostMessage API tutvustus
postMessage API pakub turvalist ja kontrollitud mehhanismi päritoluüleseks suhtluseks. See võimaldab skriptidel saata sõnumeid teistele akendele (nt iframe'id, uued aknad või vahelehed), olenemata nende päritolust. Vastuvõttev aken saab seejärel neid sõnumeid kuulata ja vastavalt töödelda.
Sõnumi saatmise põhisüntaks on:
otherWindow.postMessage(message, targetOrigin);
otherWindow: Viide sihtaknale (ntwindow.parent,iframe.contentWindowvõiwindow.openabil saadud aknaobjekt).message: Andmed, mida soovite saata. See võib olla mis tahes JavaScripti objekt, mida saab serialiseerida (nt stringid, numbrid, objektid, massiivid).targetOrigin: Määrab päritolu, kuhu soovite sõnumi saata. See on ülioluline turvaparameeter.
Vastuvõtvas otsas peate kuulama message sündmust:
window.addEventListener('message', function(event) {
// ...
});
Sündmuse event objekt sisaldab järgmisi omadusi:
event.data: Teise akna saadetud sõnum.event.origin: Sõnumi saatnud akna päritolu.event.source: Viide sõnumi saatnud aknale.
Turvariskid ja haavatavused
Kuigi postMessage pakub võimalust SOP piirangutest mööda minna, kaasnevad sellega ka potentsiaalsed turvariskid, kui seda ei rakendata hoolikalt. Siin on mõned levinumad haavatavused:
1. Sihtpäritolu mittevastavus
event.origin omaduse valideerimata jätmine on kriitiline haavatavus. Kui vastuvõtja usaldab sõnumit pimesi, võib iga veebisait saata pahatahtlikke andmeid. Enne sõnumi töötlemist veenduge alati, et event.origin vastab oodatud päritolule.
Näide (haavatav kood):
window.addEventListener('message', function(event) {
// ÄRGE TEHKE NII!
processMessage(event.data);
});
Näide (turvaline kood):
window.addEventListener('message', function(event) {
if (event.origin !== 'https://trusted-origin.com') {
console.warn('Received message from untrusted origin:', event.origin);
return;
}
processMessage(event.data);
});
2. Andmete sisestamine (Data Injection)
Vastuvõetud andmete (event.data) käsitlemine käivitatava koodina või nende otse DOM-i sisestamine võib viia saitidevahelise skriptimise (XSS) haavatavusteni. Enne kasutamist puhastage ja valideerige alati vastuvõetud andmed.
Näide (haavatav kood):
window.addEventListener('message', function(event) {
if (event.origin === 'https://trusted-origin.com') {
document.body.innerHTML = event.data; // ÄRGE TEHKE NII!
}
});
Näide (turvaline kood):
window.addEventListener('message', function(event) {
if (event.origin === 'https://trusted-origin.com') {
const sanitizedData = sanitize(event.data); // Rakendage sobiv puhastusfunktsioon
document.getElementById('message-container').textContent = sanitizedData;
}
});
function sanitize(data) {
// Rakendage siin robustne puhastusloogika.
// Näiteks kasutage DOMPurify'd või sarnast teeki
return DOMPurify.sanitize(data);
}
3. VahendajarĂĽnnakud (Man-in-the-Middle, MITM)
Kui suhtlus toimub ebaturvalise kanali (HTTP) kaudu, saab MITM-ründaja sõnumeid pealt kuulata ja muuta. Kasutage turvaliseks suhtluseks alati HTTPS-i.
4. Saitidevaheline päringu võltsimine (CSRF)
Kui vastuvõtja teostab toiminguid vastuvõetud sõnumi põhjal ilma nõuetekohase valideerimiseta, võib ründaja potentsiaalselt võltsida sõnumeid, et petta vastuvõtjat sooritama soovimatuid toiminguid. Rakendage CSRF-i kaitsemehhanisme, näiteks lisades sõnumile salajase loa (token) ja kontrollides seda vastuvõtja poolel.
5. Metamärkide kasutamine targetOrigin parameetris
targetOrigin väärtuseks * seadmine lubab igal päritolul sõnumi vastu võtta. Seda tuleks vältida, kui see pole absoluutselt vajalik, kuna see nullib päritolupõhise turvalisuse eesmärgi. Kui peate kasutama *, veenduge, et rakendate muid tugevaid turvameetmeid, näiteks sõnumi autentimiskoode (MAC).
Näide (vältige seda):
otherWindow.postMessage(message, '*'); // Vältige `*` kasutamist, kui see pole absoluutselt vajalik
Turvamustrid ja parimad praktikad
postMessage'iga seotud riskide leevendamiseks järgige neid turvamustreid ja parimaid praktikaid:
1. Range päritolu valideerimine
Valideerige alati event.origin omadus vastuvõtja poolel. Võrrelge seda eelnevalt määratletud usaldusväärsete päritolude loendiga. Kasutage võrdlemiseks ranget võrdsust (===).
2. Andmete puhastamine ja valideerimine
Puhastage ja valideerige kõik postMessage kaudu saadud andmed enne nende kasutamist. Kasutage sobivaid puhastustehnikaid sõltuvalt sellest, kuidas andmeid kasutatakse (nt HTML-i escape'imine, URL-i kodeerimine, sisendi valideerimine). Kasutage HTML-i puhastamiseks teeke nagu DOMPurify.
3. Sõnumi autentimiskoodid (MAC)
Lisage sõnumile sõnumi autentimiskood (MAC), et tagada selle terviklikkus ja autentsus. Saatja arvutab MAC-i jagatud salajase võtme abil ja lisab selle sõnumile. Vastuvõtja arvutab MAC-i uuesti sama jagatud salajase võtmega ja võrdleb seda vastuvõetud MAC-iga. Kui need ühtivad, peetakse sõnumit autentseks ja rikkumatuks.
Näide (kasutades HMAC-SHA256):
// Saatja
async function sendMessage(message, targetOrigin, sharedSecret) {
const encoder = new TextEncoder();
const data = encoder.encode(JSON.stringify(message));
const key = await crypto.subtle.importKey(
"raw",
encoder.encode(sharedSecret),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"]
);
const signature = await crypto.subtle.sign("HMAC", key, data);
const signatureArray = Array.from(new Uint8Array(signature));
const signatureHex = signatureArray.map(b => b.toString(16).padStart(2, '0')).join('');
const securedMessage = {
data: message,
signature: signatureHex
};
otherWindow.postMessage(securedMessage, targetOrigin);
}
// Vastuvõtja
async function receiveMessage(event, sharedSecret) {
if (event.origin !== 'https://trusted-origin.com') {
console.warn('Received message from untrusted origin:', event.origin);
return;
}
const securedMessage = event.data;
const message = securedMessage.data;
const receivedSignature = securedMessage.signature;
const encoder = new TextEncoder();
const data = encoder.encode(JSON.stringify(message));
const key = await crypto.subtle.importKey(
"raw",
encoder.encode(sharedSecret),
{ name: "HMAC", hash: "SHA-256" },
false,
["verify"]
);
const signature = await crypto.subtle.sign("HMAC", key, data);
const signatureArray = Array.from(new Uint8Array(signature));
const signatureHex = signatureArray.map(b => b.toString(16).padStart(2, '0')).join('');
if (signatureHex === receivedSignature) {
console.log('Sõnum on autentne!');
processMessage(message); // Jätkake sõnumi töötlemisega
} else {
console.error('Sõnumi allkirja kontroll ebaõnnestus!');
}
}
Oluline: Jagatud salajane võti peab olema turvaliselt genereeritud ja hoitud. Vältige võtme koodi sisse kirjutamist.
4. Nonce'i ja ajatemplite kasutamine
Taasesitusrünnakute vältimiseks lisage sõnumile unikaalne nonce (number used once, ühekordselt kasutatav number) ja ajatempel. Vastuvõtja saab seejärel kontrollida, et nonce'i pole varem kasutatud ja et ajatempel on vastuvõetavas ajavahemikus. See leevendab riski, et ründaja taasesitab varem pealtkuulatud sõnumeid.
5. Vähimate privileegide printsiip
Andke teisele aknale ainult minimaalsed vajalikud privileegid. Näiteks kui teine aken peab ainult andmeid lugema, ärge lubage tal andmeid kirjutada. Kujundage oma suhtlusprotokoll vähimate privileegide printsiipi silmas pidades.
6. Sisu turvalisuse poliitika (Content Security Policy, CSP)
Kasutage sisu turvalisuse poliitikat (CSP), et piirata allikaid, kust skripte saab laadida, ja toiminguid, mida skriptid saavad teha. See aitab leevendada XSS-i haavatavuste mõju, mis võivad tekkida postMessage andmete valest käsitlemisest.
7. Sisendi valideerimine
Valideerige alati vastuvõetud andmete struktuuri ja vormingut. Määratlege selge sõnumivorming ja veenduge, et vastuvõetud andmed vastavad sellele vormingule. See aitab vältida ootamatut käitumist ja haavatavusi.
8. Turvaline andmete serialiseerimine
Kasutage sõnumite serialiseerimiseks ja deserialiseerimiseks turvalist andmete serialiseerimisvormingut, näiteks JSON-i. Vältige vormingute kasutamist, mis lubavad koodi käivitamist, näiteks eval() või Function().
9. Sõnumi suuruse piiramine
Piirake postMessage kaudu saadetavate sõnumite suurust. Suured sõnumid võivad tarbida liigselt ressursse ja potentsiaalselt põhjustada teenusetõkestamise rünnakuid.
10. Regulaarsed turvaauditid
Teostage oma koodile regulaarselt turvaauditeid, et tuvastada ja lahendada potentsiaalseid haavatavusi. Pöörake erilist tähelepanu postMessage'i rakendamisele ja veenduge, et järgitakse kõiki turvalisuse parimaid praktikaid.
Näidisstsenaarium: Turvaline suhtlus iframe'i ja selle vanema vahel
Vaatleme stsenaariumi, kus iframe, mis asub aadressil https://iframe.example.com, peab suhtlema oma vanemlehega, mis asub aadressil https://parent.example.com. Iframe peab saatma kasutajaandmed vanemalehele töötlemiseks.
Iframe (https://iframe.example.com):
// Genereerige jagatud salajane võti (asendage turvalise võtme genereerimise meetodiga)
const sharedSecret = 'YOUR_SECURE_SHARED_SECRET';
// Hankige kasutaja andmed
const userData = {
name: 'John Doe',
email: 'john.doe@example.com'
};
// Saatke kasutaja andmed vanemalehele
async function sendUserData(userData) {
const encoder = new TextEncoder();
const data = encoder.encode(JSON.stringify(userData));
const key = await crypto.subtle.importKey(
"raw",
encoder.encode(sharedSecret),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"]
);
const signature = await crypto.subtle.sign("HMAC", key, data);
const signatureArray = Array.from(new Uint8Array(signature));
const signatureHex = signatureArray.map(b => b.toString(16).padStart(2, '0')).join('');
const securedMessage = {
data: userData,
signature: signatureHex
};
parent.postMessage(securedMessage, 'https://parent.example.com');
}
sendUserData(userData);
Vanemleht (https://parent.example.com):
// Jagatud salajane võti (peab ühtima iframe'i võtmega)
const sharedSecret = 'YOUR_SECURE_SHARED_SECRET';
window.addEventListener('message', async function(event) {
if (event.origin !== 'https://iframe.example.com') {
console.warn('Received message from untrusted origin:', event.origin);
return;
}
const securedMessage = event.data;
const userData = securedMessage.data;
const receivedSignature = securedMessage.signature;
const encoder = new TextEncoder();
const data = encoder.encode(JSON.stringify(userData));
const key = await crypto.subtle.importKey(
"raw",
encoder.encode(sharedSecret),
{ name: "HMAC", hash: "SHA-256" },
false,
["verify"]
);
const signature = await crypto.subtle.sign("HMAC", key, data);
const signatureArray = Array.from(new Uint8Array(signature));
const signatureHex = signatureArray.map(b => b.toString(16).padStart(2, '0')).join('');
if (signatureHex === receivedSignature) {
console.log('Sõnum on autentne!');
// Töödelge kasutaja andmeid
console.log('Kasutaja andmed:', userData);
} else {
console.error('Sõnumi allkirja kontroll ebaõnnestus!');
}
});
Olulised märkused:
- Asendage
YOUR_SECURE_SHARED_SECRETturvaliselt genereeritud jagatud salajase võtmega. - Jagatud salajane võti peab olema sama nii iframe'is kui ka vanemlehel.
- See näide kasutab sõnumi autentimiseks HMAC-SHA256.
Kokkuvõte
postMessage API on võimas tööriist päritoluülese suhtluse võimaldamiseks veebirakendustes. Siiski on ülioluline mõista potentsiaalseid turvariske ja rakendada nende riskide leevendamiseks asjakohaseid turvamustreid. Järgides selles juhendis kirjeldatud turvamustreid ja parimaid praktikaid, saate postMessage'i turvaliselt kasutada robustsete ja turvaliste veebirakenduste loomiseks.
Pidage meeles, et turvalisus on alati esmatähtis, ja hoidke end kursis veebiarenduse uusimate turvalisuse parimate praktikatega. Vaadake regulaarselt üle oma kood ja turvakonfiguratsioonid, et tagada oma rakenduste kaitse potentsiaalsete haavatavuste eest.