javascript - Hur man skyddar globala variabler (window) från att bli överskrivna


Jag arbetar för närvarande med ett projekt där säkerhet är mycket viktigt. Som standard kan alla globala variabler/egenskaper som Promise eller till och med crypto skrivas över.

Finns det ett sätt att skydda dem från att skrivas över?

Exempel :

window.crypto.getRandomValues = () => { return [1] }

window.crypto.getRandomValues(new Uint32Array(1))[0] // 1

Min första tanke var att använda Object.freeze() för att låsa objektet, men man kan enkelt skriva över Object.freeze-metoden så att den inte gör någonting.

Vi är redan mycket selektiva med de beroenden vi använder, men jag skulle ändå vilja försäkra mig om att dessa variabler inte kan skrivas över. Eller åtminstone upptäcka om de har skrivits över.

Svar #1

Disclaimer: Allt detta är bara en grov översikt, inte noggrant testat. Jag är säker på att det finns fler problem att lösa.

att frysa fönsterobjektet är inget alternativ, det skulle bara orsaka problem, men kanske objekt som window.crypto?

Men du kan omdefiniera egenskaper så att de inte längre kan ändras, även på window-objektet

function freezeProp(target, propertyName) {
  const { value, get = () => value, set = () => void 0, ...desc } = Object.getOwnPropertyDescriptor(target, propertyName);
  Object.defineProperty(target, propertyName, { ...desc, get, set, configurable: false });
}

freezeProp(window, "crypto");

Men dessa metoder fungerar bara om du kan säkerställa att du är det första skriptet som körs.

Att upptäcka om vissa metoder har ändrats är också bara möjligt om du har en referens till dem; och vi är tillbaka vid att vara det första skriptet som körs.

Men om du inte är säker på om det globala omfånget har blivit förstört, varför inte skaffa ett nytt fönsterobjekt?

window.crypto.getRandomValues = () => {
  return [1]
};

const secure = (() => {
  let iframe = document.createElement("iframe");
  document.body.appendChild(iframe);
  const contentWindow = iframe.contentWindow;
  document.body.removeChild(iframe);
  return contentWindow;
})();

var a = window.crypto.getRandomValues(new Uint8Array(1));
console.log(a);

var b = secure.crypto.getRandomValues(new Uint8Array(1));
console.log(b);