0

I'm trying to add a "tab namespace" to all local storage keys so that I can achieve a uniqueness of local storage for sites between multiple tabs.

In a simple HTML5 page, let's say a web page has the following script:

Storage.prototype._setItem = Storage.prototype.setItem;
Storage.prototype.setItem = function(key, value) {
    console.log("intercepted set local storage " + key + " = " + value);
    this._setItem(key, value);
}

Storage.prototype._getItem = Storage.prototype.getItem;
Storage.prototype.getItem = function(key) { 
    console.log("intercepted get local storage " + key);
    return this._getItem(key);
}

This gives the user a chance to intercept all gets/sets to the local storage.

Now let's say you have an extension doing the same thing:

var actualCode = `Storage.prototype._setItem = Storage.prototype.setItem;
Storage.prototype.setItem = function(key, value) {
    console.log("intercepted set local storage " + key + " = " + value);
    this._setItem(key, value);
}

Storage.prototype._getItem = Storage.prototype.getItem;
Storage.prototype.getItem = function(key) { 
    console.log("intercepted get local storage " + key);
    return this._getItem(key);
}

console.log("local storage get/set injector completed");
`;

var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.remove();

You will get a stack overflow when you have this extension enabled while loading the page with the script above:

Uncaught RangeError: Maximum call stack size exceeded
at Storage.getItem [as _getItem] (<anonymous>:48:37)
at Storage.getItem [as _getItem] (<anonymous>:50:17)
at Storage.getItem [as _getItem] (<anonymous>:50:17)
at Storage.getItem [as _getItem] (<anonymous>:50:17)
at Storage.getItem [as _getItem] (<anonymous>:50:17)
at Storage.getItem [as _getItem] (<anonymous>:50:17)
at Storage.getItem [as _getItem] (<anonymous>:50:17)
at Storage.getItem [as _getItem] (<anonymous>:50:17)
at Storage.getItem [as _getItem] (<anonymous>:50:17)
at Storage.getItem [as _getItem] (<anonymous>:50:17)

Is there some way to detect that someone has already done an intercepted local storage and prevent the issue?

Nicholas DiPiazza
  • 10,029
  • 11
  • 83
  • 152
  • 2
    I can't reproduce if I put this code in a normal js file inside an extension. It's not clear why you append this code to your extension page as an inline script element which doesn't even run unless you relax the default CSP (bad idea; it's better to use sandbox pages). I also think it's better to use `Proxy` API because getItem isn't invoked for direct access like `localStorage.foo`. – wOxxOm Jun 23 '18 at 18:21
  • I just hit that issue right as you mentioned it. I'll take a look at the `Proxy` api – Nicholas DiPiazza Jun 23 '18 at 18:24
  • Do you know of any examples of using it that are similar to this? It looks fairly non-trivial – Nicholas DiPiazza Jun 23 '18 at 18:25
  • by the way i updated the question above. it was only doing the stackoverflow because the htmlpage i was loading also had the same prototype hack. – Nicholas DiPiazza Jun 23 '18 at 18:39
  • Save the previous getItem reference in a local variable (maybe inside a closure). That's how it's always been done while your approach is uhm... living-on-the-edge! – wOxxOm Jun 23 '18 at 18:43
  • are the answers on this question correct? https://stackoverflow.com/questions/33888685/override-dot-notation-for-localstorage they have no votes but i'm giving them a gander. – Nicholas DiPiazza Jun 23 '18 at 18:46

0 Answers0