Warm tip: This article is reproduced from stackoverflow.com, please click
iframe server http-referer

Server side detection iframe

发布于 2020-04-10 10:04:56

Related issues: Server-side detection that a page is shown inside an IFrame

I find weird that we can't apparently know from the server side if whether the page is loaded through an iframe. Most answers say that it's only detectable from the browser, I just don't get why.

In the browser, we have access to document.referrer which clearly indicates the url we come from. There is something similar on the server side using req.headers.referer.

I just tested it with a local iframe and I got the following results:

referer http://localhost:8888/tests/chatbotIframeIntegration // The page containing the iframe
referer http://localhost:8888/chatbot // The page displayed within an iframe
referer undefined // seems to be undefined sometimes, maybe due to HMR?)

I can definitely detect the url the request comes from. So, if I know what url my app should be running into, I can definitely have some logic that figures out whether I'm calling my server from an external website, can't I?

Also, it's quite weird that the browser uses referrer and the server uses referer (one r)...

Questioner
Vadorequest
Viewed
42
Vadorequest 2020-02-26 21:34

I've gained more experience through experimentation, so here is what I've learned so far.


As I thought, we can resolve the referrer through document.referrer (browser) and req.headers.referer (server).

So, it's possible to detect whether the current referrer is different than what's our hosting server, and in this case we know the query comes from an iframe.

It gets trickier when you want to know, from the server side, if a page within your site has been loaded through an iframe within that same site. In such case, there is no way to automatically detect whether we're running the page from an iframe or not.

For instance, if you have an iframe on page /index that loads /page2 page, then you can't know, from the server side if /page2 was loaded from the iframe (on /index) or from navigating to /page2.

And that's why people say there is no way to know, from the server side, if a page was loaded through an iframe. Because it's uncertain.


Now, my actual need was a little different. I needed to know if my /page2 was loaded from another domain that my own (cross domain), and that is fairly simple to know, because the referrer will be different that my own domain, both on the server side and browser side.

It got a bit more complex with my integration tests, because I had a /tests/iframeIntegration page that contains an iframe which loads another page /page2, from the same domain. (relative url)

The point was to test whether the iframe integration worked as expected, and because it was running on the same domain, I couldn't resolve whether I was loading it through an iframe.

For this particular case, I added a /page2?iframe=true in the url. It's the simplest workaround I've found that works universally (browser + server).

Here are a few utility scripts:

import { isBrowser } from '@unly/utils';
import includes from 'lodash.includes';

/**
 * Resolves whether the current web page is running as an iframe from another page
 *
 * Iframes are only detectable on the client-side
 * Also, using iframe=true as search parameter forces iframe mode, it's handy when using an iframe from the same domain
 * (because same-domain iframes aren't detected when comparing window.parent and window.top since it's the same window)
 *
 * @return {boolean}
 * @see https://stackoverflow.com/a/326076/2391795
 */
export const isRunningInIframe = (): boolean => {
  if (isBrowser()) {
    try {
      return window.self !== window.top || includes(document.location.search, 'iframe=true');
    } catch (e) {
      return null; // Can't tell
    }
  } else {
    return null; // Can't tell
  }
};

/**
 * Resolve the iframe's referrer (the url of the website the iframe was created)
 *
 * Helpful to know which of our customer use our app through an iframe, and analyse usage
 * May not always work due to security concerns
 *
 * @return {string}
 * @see https://stackoverflow.com/a/19438406/2391795
 */
export const getIframeReferrer = (): string => {
  if (isRunningInIframe()) {
    try {
      return document.referrer || null;
    } catch (e) {
      return null;
    }
  } else {
    return null;
  }
};