18

I have a Widget that I created and I am embedding it on other websites using an iFrame. What I want to do is make sure no one can view the source and copy the iFrame code and put it on their own website.

I can store the URL that it should be allowed on in the database. I've seen it done before, one site had a long encrypted code and if it didn't match with the domain then it said Access Denied..

Does anyone know how I can do this?

Thanks!

Drew
  • 6,736
  • 17
  • 64
  • 96

6 Answers6

21

No you can't do this. The best thing you can do is the following:

if (window.top.location.host != "hostname") {
    document.body.innerHTML = "Access Denied";
}

Add the above to your JavaScript and then use a JavaSript obfuscator

noob
  • 8,982
  • 4
  • 37
  • 65
  • 1
    I corrected your DOM reference to `window.top.location.host` - which will refer to the host of the top frame (the site that is trying to embed the widget) and not `window.location.host` which will be the host that serves the widget. – Cheekysoft Nov 17 '11 at 15:42
  • 1
    When I add this to my code and look at the site it is embedded on in Firebug, I get this: "Permission denied to access property 'host'" – Drew Nov 17 '11 at 16:46
  • @Drew just check window.top.location, then – Cheekysoft Nov 17 '11 at 17:32
  • so why not just `view-source://url_to_iframe` ? Or fetch it with CURL. – rook Nov 17 '11 at 18:02
  • 4
    @Cheekysoft this wouldn't work in a cross domain site. It gives Permission denied to access property host in firebug – MarutiB Aug 16 '12 at 08:18
  • @MarutiB you're right, but the problem is in accessing the `.host` property; `window.top` is not the cause. In a cross-domain situation, you'll need to test just `location` instead of `location.host` – Cheekysoft Aug 17 '12 at 14:08
  • 1
    In a cross-domain situation any property of window.top would be empty, so you can't check location either. – Mike Garcia Sep 19 '14 at 06:43
  • so if javascript is disabled on iframe using `sandbox` this will be useless – Muhammad Umer Jul 11 '16 at 14:46
  • While this answer has some serious technical flaws that prevent it from working, the general approach was alright back in the day. [weiyin's answer](https://stackoverflow.com/a/35514590/19068) is the best approach to solving this problem from about 2010 onwards – Quentin Jul 26 '21 at 19:00
14

You cannot prevent people from looking at your HTML, but there are some headers can allow you to specify what sites can embed your iframe. Take a look at the X-Frame-Options header and the frame-ancestors directive of Content-Security-Policy. Browsers that respect it will refuse to load the iframe when embedded into someone else's site.

weiyin
  • 6,819
  • 4
  • 47
  • 58
5

On the server in the code for the page displayed in the IFRAME, check the value of the Referer header. Unless this header has been blocked for privacy reasons, it contains the URL of the page which hosts the IFRAME.

Dark Falcon
  • 43,592
  • 5
  • 83
  • 98
  • referrer can easily be spoofed. Never rely on it (or any other HTTP header) – Cheekysoft Nov 17 '11 at 15:43
  • 8
    Certainly it can be, but some arbitrary client browser WON'T be spoofing. He is not asking to prevent people from viewing his source, he just wants to prevent people from putting the frame on their own site. – Dark Falcon Nov 17 '11 at 19:20
1

What you are asking for is pretty much impossible. If you make the source available on the web someone can copy it one way or another. Any javascript tricks can be defeated by using low level tools like wget or curl.

So even if you protect it, you're still going to find that someone could in theory copy the code (as the browser would receive it) and could if so determined put it on their own website.

Mech
  • 2,904
  • 3
  • 24
  • 29
  • It *is* impossible to stop someone viewing how the widget is embedded, but is not impossible to stop your widget from functioning correctly, if it can determine it has been iframed in to somewhere it doesn't want to be. – Cheekysoft Nov 17 '11 at 15:45
  • 1
    @Cheekysoft I agree you can make it inoperable but this sort of solution wont work for the determined. That line of code could easily be run through a PHP file using file_get_contents and have the line replaced with a static value defeating it completely. – Mech Nov 17 '11 at 15:49
  • A very good point; You're absolutely right. If the widget relied on communication back to mothership to function, then this could be remediated. Put some of the key functionality on your server and call it with XHR, which will have to confirm to Same Origin Policy and thus fail if someone alters and republishes the JS code. – Cheekysoft Nov 17 '11 at 15:58
  • @Cheekysoft Exactly. However this can be solved by not embedding it into the iframe. Have the js code itself create the iframe on the page so that way the origin is always correct. Granted this can still be spoofed but far harder to use at that point. – Mech Nov 17 '11 at 16:16
  • Mind you, I guess this only raises the bar. The XHR calls can still be statically re-written to calls to evil.com that then make server-to-server requests for the XHR URLs. Thinking about this, I can't see how you could ever completely stop it. But i'm sure for most widgets, @micha's answer will provide "enough" security. The question is "will anyone actually want to unobfuscate and rewrite your code, in order to be able to embed your widget?" If the investment in time is greater than the perceived value, then people simply aren't going to bother. – Cheekysoft Nov 17 '11 at 16:19
  • 1
    @Cheekysoft I think it greatly depends on the widget. If it was a simple widget you would think no security would be required whatsoever. – Mech Nov 17 '11 at 16:24
0

I faced the same problem, but I return the user on a home page. I spread the decision.

It has to be placed where there is iframe

<script>
        $(window).load(function () {
            var timetoEnd = '';   
            var dstHost   = 'YOUR-ALLOW-HOST';
            var backToUrl = 'BACK-TO-URL';

            function checkHost(){
                var win = window.frames.YOUR-IFRAME-NAME;
                win.postMessage('checkHost', dstHost);
                    console.log('msg Sended');
                    clearInterval(timetoEnd);
                    timetoEnd = setInterval(function () {
                        window.location.href = backToUrl;
                    }, 5000);
                }

                function validHost(event) {
                    if (event.data == 'checkHostTrue') {
                        clearInterval(timetoEnd);
                        console.log('checkHostTrue');
                    } else {
                        return;
                    }
                }

                window.addEventListener("message", validHost, false);
                checkHost();

                setInterval(function () {
                    checkHost();
                }, 10000
                );
            });
    </script>

It has to be placed into your src iframe

<script>
            function receiveMessage(event)
            {
                if(event.data=='checkHost'){
                    event.source.postMessage("checkHostTrue",
                           event.origin);
                } else {
                    return;
                }
            }
            window.addEventListener("message", receiveMessage, false);
</script>
Sergey
  • 9
  • 1
-1

I know it's kinda old topic but I have code that you just put in <script> tag and it should prevent most of curious people from looking at html files from iFrame:

if(window.top.location.pathname === window.location.pathname){
history.back()
}
Ole Pannier
  • 3,208
  • 9
  • 22
  • 33
KubaTM
  • 1
  • This will throw an exception before hitting `history.back` … and going back from the first page in the frame's history would take you to the page you are already on. – Quentin Jul 26 '21 at 18:56
  • [This answer](https://stackoverflow.com/a/35514590/19068) is the sensible one today. – Quentin Jul 26 '21 at 18:58