Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: origin whitelist for child #150

Open
mrcoles opened this issue Jan 31, 2019 · 3 comments
Open

Feature request: origin whitelist for child #150

mrcoles opened this issue Jan 31, 2019 · 3 comments

Comments

@mrcoles
Copy link

mrcoles commented Jan 31, 2019

What Is the issue?

I would love for the child to be able to set an origin whitelist, which—if set—means it will only handshake with origins that are in its whitelist.

Provide issue context below using code examples, images, or links

It could look something like this:

new Postmate.Model({
  height: () => document.height || document.body.offsetHeight
}, {
  originWhitelist: ['http://localhost:1234', 'https://example.com']
});

and then inside Postmate.Model.sendHandshakeReply (assuming the constructor sets the 2nd arg as this.opts) it could do something like this:

        if (e.data.postmate === 'handshake') {
          this.child.removeEventListener('message', shake, false);

          // whitelist check
          if (this.opts.originWhitelist && this.opts.originWhitelist.length) {
            if (!this.opts.originWhitelist.find(origin => sanitize(e, origin))) {
              return reject(`Invalid origin: ${e.origin}`);
            }
          }

          // … rest of function…
        }
@mrcoles
Copy link
Author

mrcoles commented Jan 31, 2019

I can always do this extra check post-handshake, but it’s more secure to do it pre-handshake. By checking pre-handshake, the child never sends a postMessage to untrusted parent origins (post-handshake it happens after). This prevents non-trusted origins from sniffing if there was a child accepting handshakes or not—which is relevant if the child page is behind a login or if it is a Chrome extension.

Here’s a wrapper for Postmate.Child that does the check post-handshake (but my snippet in the issue description would do the pre-handshake check):

import Postmate from "postmate";

class OriginChecker {
  constructor(originWhitelist) {
    this.originWhitelist = originWhitelist;
    this.isValid = true;
  }

  validate(parentOrigin) {
    if (this.originWhitelist.indexOf(parentOrigin) === -1) {
      this.isValid = false;
    }
    return this.isValid;
  }

  wrapModel(model) {
    const ret = {};
    Object.entries(model).forEach(([key, val]) => {
      ret[key] = data => {
        if (this.isValid) {
          return typeof val === "function" ? val(data) : val;
        } else {
          throw new Error("Invalid origin");
        }
      };
    });
    return ret;
  }
}

const makePostmateModel = (model, originWhitelist) => {
  const originChecker = new OriginChecker(originWhitelist);

  const handshake = new Postmate.Model(originChecker.wrapModel(model)).then(
    parent => {
      if (!originChecker.validate(parent.parentOrigin)) {
        const err = new Error(`Invalid parent origin: ${parent.parentOrigin}`);
        err.name = "InvalidParentOriginError";
        throw err;
      }

      return parent;
    }
  );

  return handshake;
};

export default makePostmateModel;

@jakiestfu
Copy link
Contributor

This is something Postmate should definitely solve. Can we assume that the iFrame provided will have a src of the origin we expect? It'd be nice to automate this and not have to provide any additional config.

@Lynn-cc
Copy link

Lynn-cc commented Dec 12, 2020

I have the same question, imaging that there's anther parent origin,use the same way to connect to my child site, he can read all the data that the child set, and call all the functions the child site declared. This may cause secure problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants