6

I'm building a site where anyone will be able to interact with my iFrame through the postMessage command (i.e. sandboxed functions, not total control of the window). How can I do that without exposing my visitor's cookies through XSS? https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Security_concerns

Let's say I have the following receive function:

var secret = localStorage.getItem("secret");

window.addEventListener(message,function(e){
     // any e.origin is allowed
     if(e.func=="doX"){
            var string = e.data.string1 * e.data.string2;

     }else if(e.func=="doY"){
            // another javascript function, no DOM interaction
            config[e.data.key] = e.data.value;

     }else if(e.func=="doZ"){
          document.getElementById("app")=e.data.title
          document.getElementById("description")=e.data.description
     }
})


I read on the Mozilla page that allowing request from any origin is pretty dangerous. How can I properly prevent XSS for each of the doX, doY, and doZ scenarious?

I gave it a try too. Are these functions safe?

var secret = localStorage.getItem("secret");

window.addEventListener(message,function(e){
     // any e.origin is allowed
     if(typeof e.func!=Number) return;

     if( e.func < 0 || e.func > 2) return;

     if(e.func==0){ //  we will call this "Safe 0"

            if(e.data.num1 > 1000 || e.data.num2 > 1000) return;
            var num3 = e.data.num1 * e.data.num2;

     }else if(e.func==1){ // safe 1

            if(!isHex(e.data.value))return; // see below for isHex func

            config['something'] = e.data.value;

     }else if(e.func==2){ // safe 2

          if(e.data.title.length < 8) document.getElementById("app")=e.data.title;

          if(e.data.description.length < 15)document.getElementById("description")=e.data.description

     }
})
function isHex(h) {

    var a = parseInt(h,16);
    return (a.toString(16) === h)

}

I have learned that HTML input elements will also be inaccessible from the hosting site, meaning that these "postMessage"s are the main source of vulnerability. Source for this last statement: Get value of input field inside an iframe

nick carraway
  • 212
  • 2
  • 15
  • They can replace everything using Proxy object. And so can you, to manipulate normal execution and call home etc, add Mutation Observer to safeguard your DOM (i.e. change post message. That is, if postmessage is called always return string “no no no...”) – Gillsoft AB Feb 22 '19 at 20:54
  • Remember, browsers are stupid, if you (or anyone else) tell a browser your request header field “host” = x or “origin” = y or any other field, it will blindly trust it as a fact... – Gillsoft AB Feb 22 '19 at 21:01
  • User A visits a website owned by user B. User B's website has an iFrame hosting Facebook.com, where the Facebook.com iFrame accepts messages from any origin. With this permission, can the Website Owner, User B, manipulate the Facebook iFrame embedded in his site, to access user A's facebook login token from local storage? Assume facebook iframe allows messages to be received from any origin, can user B still inject `new Function() `, etc, to get facebook-only variables particular to user A? How would you prevent this? – nick carraway Feb 22 '19 at 21:02
  • Yes I have done it personally in a widget for a partner company. The main site (window.top.location) own the rights, and your ability to limit anything is slim. But make a proxy as I said to be aware of anything they do. – Gillsoft AB Feb 22 '19 at 21:06
  • Can you explain how this is done in an answer? I'm not sure you're reading my question correctly. The main site (of user B) doesn't "own the rights" to a facebook contentWindow in an iFrame. That's the whole reason iFrames exist in the first place..... Again, I just want to know if User A's data is safe, or what kind of message can be put through in `postMessage` that would allow you to access the DOM, because I don't believe there are any. Please provide a resources if there is – nick carraway Feb 22 '19 at 21:07
  • 1
    The way I do it is using websockets (they are not affected by cors etc) and you can communicate with clients directly on the website that is not yours. Thus, you don’t need to save any data in localstorage/cookie. – Gillsoft AB Feb 22 '19 at 21:09
  • That is interesting and probably good to know for future use. But I'm still not sure we are speaking the same language here yet – nick carraway Feb 22 '19 at 21:12
  • Remember the web browser is on ”your” site in a part of the screen/window. The risks you mention goes both ways. To answer your question: No, whatever data the user read/write is not safe, you only need to think/calculate the risk of it to happen. To describe in detail how and why is to describe the attack vectors Quentin mentioned. – Gillsoft AB Feb 22 '19 at 21:22
  • I have added even more examples, thanks for your help and @Quentin too – nick carraway Feb 22 '19 at 21:34

2 Answers2

2

As long as I don't run an eval statement on messages sent using the postMessage function to my window, is there any way arbitrary code can be executed?

Any of the usual client-side JS XSS attack vectors are open.

So as well as eval, you have various eval-by-proxy features (such as new Function()), the effect of inserting data from the message into the DOM in an unsafe fashion, etc.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • Can you go into more explict detail about how this would be done? Say i have a sensitive variable contained in the word `var secretkey` and/or another sensitive variable contained in `localStorage` called `secretkey`... How do I make sure these iframe messages don't call `new Function()` and access them? – nick carraway Feb 22 '19 at 16:05
  • Or, I guess what I would rather ask is, how can I make sure that this doesn't happen? Do I need to make a list of valid messages or input types? E.g. if the possible colors are red,blue,green, create a list with those strings, and make sure the input message is only those colors? Second e.g.: if the input is supposed to be a float, make sure has type Number. But what if I want to allow other origins to add an arbitrary string to a div tag? Is that possible or a risk? – nick carraway Feb 22 '19 at 19:13
  • Please see added examples – nick carraway Feb 22 '19 at 21:37
1

As far as I can tell, XSS vulnerabilities are better considered on a case-specific level. It's not just about getting the variable safely into your window through postMessages, it's what you do with the variable once its there. Like, you wouldn't want to take in a variable argument and download a script, since the variable could be changed to download a malicious script. You wouldn't run an eval statement. I am still not sure if "evalByProxy" applies in a purely javascript environment (no HTML / input element manipulation; No communication to a database). Since I asked the other answerer for clarification on this and I can't find any information on it through Google, I assume that this is not really an issue as long as I don't communicate the iFrame message to a server database, the DOM, or run an eval statement. Look more into basic XSS chatroom examples for an example of why sending these messages to a server is a bad idea.

What I found to be a greater security threat in the case of trying to keep an iFrame secure is the existence of browser extensions (e.g. adblockers). These receive permission to access every part of a web page. This means they can access any global variable in your webpage and any global function. I am not sure yet if they can access locally-scoped variable (e.g. inside an object). I am not sure if they can access localStorage but I would guess that they can. So I ended up continuing gently in the space of XSS messages and am reconsidering any method that involves localStorage.

nick carraway
  • 212
  • 2
  • 15