Cross-domain hash change communication - javascript

Please consider the following two domains: domain1.com and domain2.
From domain1 I open an iframe that points to domain2.
Now, I want these guys to communicate with each other, which I've successfully accomplished by applying hash change event listeners on both domains.
That way, the hash in the parent window (domain1) will trigger if domain2 calls parent.location with a new hash. Also, the hash change event triggers in the iframe if I from the parent changes its src attribute to a new hash.
This works great!
Here comes the trouble:
The back and forward functionality in the browser gets messed up. Simply put, by creating two hash instances, the browser back button has to be clicked twice to get the parent hash to change since it has to cycle through the iframe's hash first.
How can I communicate with a cross-domain iframe 2-way without screwing up the history object?
Thanks!

Use easyXDM, it's a javascript library that does all the hard work for you, enabling you to do cross-domain communication and RPC in all browsers, including IE6.
This will not use the HashTransport for any of the current browsers (not even IE6), and so will not change the history.
You will not find anything better..
You can read about some of its inner workings in this Script Junkie article, or go straight to the readme at github

Another technique for crossdomain communications is (ab)using window.name. It requires an iframe to originally have a same-domain src initially after which you move to another domain that sets the window.name and then steps back to the original source (step back in history). The idea is that the window.name does not change unless it's explicitly set, this means you can transfer window.name data cross domain.
This technique is described in more detail on:
- http://skysanders.net/subtext/archive/2010/10/11/leveraging-window.name-transport-for-secure-and-efficient-cross-domain-communications.aspx
- http://jectbd.com/?p=611
Be sure to choose the implementation that avoids clicking sounds in IE.
Unfortunatly, it still messes around with your history, but it does a step forward and then backwards to the history point it was at. A big benefit though, is that you don't have to parse and encode URI strings, but can use JSON right away.
Using JSON lib for example
// access window.name from parent frame
// note: only when iframe stepped back to same domain.
var data = JSON.parse( iframe.contentWindow.name );
// set child frame name
// note: only when iframe stepped back to same domain.
iframe.contentWindow.name = JSON.stringify( {
foo : "bar"
} ); // to JSON string
// set own name ( child frame )
window.name = JSON.stringify( {
foo : "bar"
} ); // to JSON string
The cookie technique is viable as well, for both techniques you need to perform ajax requests in the target iframe if you want to avoid history changes but still require http request.
so:
Send data to iframe x (using cookie or window.name technique)
Catch data with poller in iframe x
Perform ajax requests in iframe x.
Send data back to iframe y (using cookie or window.name technique)
Catch data with poller in iframe y
Do the hokey pokey.
Any page refresh (httprequest) or url change will update the history (except for old or all IE versions), so more code is required alas.

Related

How to change browser url without changing anything in history

You might think this is a duplicate, but it's not. I've seen the other SO answers about changing the browser url with replaceState() but I have a problem...
On one webpage on my website, it receives a lot of parameters, so the link goes on and on and on... I did replaceState(), and it shortened the URL by a lot. That worked. If I go on another link, and I go back in history, the URL will still be the same that I defined on replaceState() and the page gives a 404 error. Is there a way to just load the link the way it is and then temporarily change the URL so the user doesn't see a huge link but the system uses the actual URL?
I'm using JSP, go ahead and give me answers in JavaScript, JQuery, or Java.
You could store the parameters in localstorage (ie a cookie) then have your next page un-pick them from localstorage, thus reducing the size needed of the URL in the frst place. Example code (stolen from Storing Objects in HTML5 localStorage) :
// add to storage
localStorage.setItem('myAttibute', 'acceptable');
// Retrieve the object from storage (on another page)
var sMyAttibute= localStorage.getItem('myAttibute');
alert("myAttibute=" + sMyAttibute);
Hopefully it'll tell you that my attribute is acceptable.

How To Access Child Window URL from Parent Window?

I am redirecting my child window to another url after launching. Actually I am submitting the data to another domain. That domain processing the data and sends to new domain. I need to catch the new domain URL.
I don't think you'll be able to do that. You can't access frames/windows from different origin - that's simply not safe and the browser won't let you.
You could try to work it out differently.
For example, I believe you could have your server side get the other website for you and serve it in your own domain. If you decide to do that, you need to have the reference to your child window first (e.g. var win = window.open(url);) - but still, that needs to be in your domain.
Another way would be to simply post your data using your server side language and then try to read the received page (also using server side). In PHP for example, you could accomplish that with cURL and Simple HTML Dom Parser.
Edit
Just came upon window.postMessage functionality. If the other websites are yours, I think that's the way to go (well, maybe except the limited compatibility in IE 8 & 9: Can I use postMessage).

Cross domain javascript form filling, reverse proxy

I need a javascript form filler that can bypass the 'same origin policy' most modern browsers implement.
I made a script that opens the desired website/form in a new browser. With the handler, returned by the window.open method, I want to retrieve the inputs with theWindowHandler.document.getElementById('inputx') and fill them (access denied).
Is it possible to solve this problem by using Isapi Rewrite (official site) in IIS 6 acting like a reverse proxy?
If so, how would I configure the reverse proxy?
This is how far I got:
RewriteEngine on
RewriteLogLevel 9
LogLevel debug
RewriteRule CarChecker https://the.actualcarchecker.com/CheckCar.aspx$1 [NC,P]
The rewrite works, http://ourcompany.com/ourapplication/CarChecker, as evident in the logging. From within our companysite I can run the carchecker as if it was in our own domain. Except, the 'same origin policy' is still in force.
Update,
I stopped using Isapi Rewrite as the free version does not include a proxy component. I started to use the url rewriter from Managed Fusion.
My current working rewriterule:
RewriteRule /MySecuredSite/CarChecker https://the.actualcarchecker.com [NC,P]
Now I get the error: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
I think this occurs because our ssl-certificate is passed on to the carchecker site. How can I configure the reverse proxy so that the certificate of the carchecker site is passed on?
Regards,
Michel
Without knowing a few more details I decided that it might just be helpful to list some of the restrictions you face and some of the tricks you could take advantage of:
I'm not an ASP developer but I'm aware that, as you mentioned, there is some kind of viewstate variable that must be submitted along with a ASP form. I assume that this viewstate can be validated using only the form fields that are to be resubmitted. That's all that I'd expect (unless it's super complex) since the form the browser receives is all it sends back (along with values). So the point is that you'll need a valid viewstate when you submit to the aspx page, but maybe you can grab any viewstate you want from the server so long as the form fields you submit are identical.
You can write a webpage that acts just like your browser does. It can grab the aspx page (thus establishing a valid viewstate), then you can create all of the fields necessary to POST to the aspx page, including the viewstate, and do so. Whatever the results are can be returned from your webpage to the browser. Unless you have the ability to modify the other server I really don't see another option at this point, but maybe someone else can be more helpful.
If you can modify the other server then you have a few other options. One of them involves a trick for passing data between iframes. If you're using a hidden iframe to get the aspx page then you won't be able to get the result back to the parent page due to the cross-domain restriction. But since you can modify the other server (running on the.actualcarchecker.com), you can get around this. To do so just make that server provide JavaScript to submit the form asynchronously and then set the result (serialized to a string) to window.name.
Now to get access to window.name from your domain, you set the iframe's window.location to a page on your domain that will simply call a function you wrote in the JavaScript loaded in the parent window. Like window.parent.process(window.name). Since the iframe loaded a page on your domain it will have access to window.name which will not have been changed even though you changed window locations. Then the process() function in the parent window can deserialize the string, remove the hidden iframe, show the results, do whatever you want, etc.
You won't be able to populate the aspx form that's loaded in the hidden iframe unless you do a similar trick on the other domain's server. That server's JavaScript will need to read from window.name to receive the inputs to populate the form with. However, if both servers are in on the trick then you don't have to write a proxy, you can just pass data via window.name.
Which server side language are you using? Using it you can create a proxy which should easily bypass the one domain policy...
PHP
<?php
$handle = fopen("https://the.actualcarchecker.com/CheckCar.aspx", "r");
$contents = '';
while (!feof($handle)) {
$contents .= fread($handle, 8192);
}
fclose($handle);
echo $contents;
?>
I'd imagine it would be a similar process with other languages.
Why don't you use JSONP approach instead? I.e. use JavaScript to read the values entered into your form and sent it to the server-side handler via a dynamically generated <script> element (<script> and img elements can refer to resources from external domains).
var e = document.createElement("script");
e.setAttribute("type", "text/javascript");
e.setAttribute("src", "https://the.actualcarchecker.com/CheckCar.aspx?input1=value1&input2=value2");
document.getElementsByTagName('head')[0].appendChild(e);
Likely, you will not need any serious URL rewriting at all if you use this approach - just make sure that CheckCar.aspx returns valid JSON.
JQuery even has several convenience functions for this: AFAIK $.getJSON will transparently switch from XHR to dynamic script insertion method if the request is cross-domain. Also, it supports specifying callbacks. See jQuery docs and this IBM article for more info.
Will this method work for you?

get referer of website that is requesting your js file

I have an embed script that simply does this:
document.write(unescape('%3Cscript src="' + mp_protocol + 'blah.cloudapp.net/js?location="' + window.location +' type="text/javascript"%3E%3C/script%3E'));
As you can see right now the URL of the webpage that is embedding the code is passed in using window.location. But this can easily be edited by the client.
I wanted to know if I can get the referrer instead of passing the url. I wasn't sure if referring info would be passed since this script is embedded?
(yes, you can also fake referrers... but that is a bit more effort than I think most people will want).
The browser will usually send a "Referer" (sic) header for script requests which contain the URL of the page that contains the script link, regardless of how that script element was created.
This is accessible by checking the "Referer" HTTP variable (note unusual spelling).
The idea is that you can check this variable and see if it refers to part of your site.
Note that this variable is not always accurate; a user may elect to protect their privacy by not sending a referer header (using some sort of dinky privacy tool) and they may even modify their browser to send whatever they want in this field. So it shouldn't be relied upon for authentication, unless you also take into account that even a legitimate user may have left it blank or put an arbitrary string in it.

How to get javascript in an iframe to modify the parent document?

So I have two documents dA and dB hosted on two different servers sA and sB respectively.
Document dA has some JS which opens up an iframe src'ing document dB, with a form on it. when the form in document dB is submitted to a form-handler on server sB, I want the iframe on page dA to close.
I hope that was clear enough. Is there a way to do this?
Thanks!
-Mala
UPDATE: I have no control over dA or sA except via inserted javascript
This isn't supposed to be possible due to browser/JavaScript security sandbox policy. That being said, it is possible to step outside of those limitations with a bit of hackery. There are a variety of methods, some involving Flash.
I would recommend against doing this if possible, but if you must, I'd recommend the DNS approach referred to here:
http://www.alexpooley.com/2007/08/07/how-to-cross-domain-javascript/
Key Excerpt:
Say domain D wants to
connect to domain E. In a nutshell,
the trick is to use DNS to point a
sub-domain of D, D_s, to E’s server.
In doing so, D_s takes on the
characteristics of E, while also being
accessible to D.
Assume that I create page A, that lies withing a frame that covers the entire page.
Let A link to yourbank.com, and you click on that link. Now if I could use javascript that modifies the content of the frame (banking site), I would be able to quite easily read the password you are using and store it in a cookie, send it to my server, etc.
That is the reason you cannot modify the content in another frame, whose content is NOT from the same domain. However, if they ARE from the same domain, you should be able to modify it as you see fit (both pages must be on your server).
You should be able to access the iframe with this code:
window["iframe_name"].document.body
If you just want the top-level to close, you can just call something like this:
window.top.location = "http://www.example.com/dC.html";
This will close out dA and sent the user to dC.html instead. dC.html can have the JS you want to run (for example, to close the window) in the onload handler.
Other people explained security implications. But the question is legitimate, there are use cases for that, and it is possible in some scenarios to do what you want.
W3C defines a property on document called domain, which is used to check security permissions. This property can be manipulated cooperatively by both documents, so they can access each other in some cases.
The governing document is DOM Level 1 Spec. Look at the description of document. As you can see this property is defined there and … it is read-only. In reality all browsers allow to modify it:
Mozilla's document.domain description.
Microsoft's domain property description.
Modifications cannot be arbitrary. Usually only super-domains are allowed. It means that you can make two documents served by different server to access each other, as long as they have a common super-domain.
So if you want two pages to communicate, you need to add a small one-liner, which should be run on page load. Something like that should do the trick:
document.domain = "yourdomain.com";
Now you can serve them from different subdomains without losing their accessibility.
Obviously you should watch for timing issues. They can be avoided if you establish a notification protocol of some sort. For example, one page (the master) sets its domain, and loads another page (the server). When the server is operational, it changes its domain and accesses the master triggering some function.
A mechanism to do so would be capable of a cross-site scripting attack (since you could do more than just remove a benign bit of page content).
A safe approach would limit to just the iframe document emptying/hiding itself, but if the iframe containing it is fixed size, you will just end up with a blank spot on the page.
If you don't have control over dA or Sa this isn't possible because of browser security restrictions. Even the Flash methods require access to both servers.
This is a bit convoluted but may be more legitimate than a straight XSS solution:
You have no control over server A other than writing javascript to document A. But you are opening an iframe within document A, which suggests that you only have write-access to document A. This a bit confusing. Are you writing the js to document A or injecting it somehow?
Either way, here is what I dreamed up. It won't work if you have no access to the server which hosts the page which has the iframe.
The user hits submit on the form within the iframe. The form, once completed, most likely changes something on the server hosting that form. So you have an AJAX function on Document A which asks a server-side script to check if the form has been submitted yet. If it has, the script returns a "submitted" value to the AJAX function, which triggers another js function to close the iframe.
The above requires a few things:
The iframe needs to be on a page hosted on a server where you can write an additional server-side script (this avoids the cross-domain issue, since the AJAX is pointing to the same directory, in theory).
The server within the iframe must have some url that can be requested which will return some kind of confirmation that the form has been submitted.
The "check-for-submitted" script needs to know both the above-mentioned URL and what to look for upon loading said URL.
If you have all of the above, the ajax function calls the server-script, the server-script uses cURL to go the URL that reflects if the form is done, the server-script looks for the "form has been submitted" indicators, and, depending on what it finds, returns an answer of "not submitted" or "submitted" to the ajax function.
For example, maybe the form is for user registration. If your outer document knows what username will be entered into the form, the server-side script can go to http://example.org/username and if it comes up with "user not found" you know the form has yet to be submitted.
Anything that goes beyond what is possible in the above example is probably outside of what is safe and secure anyway. While it would be very convenient to have the iframe close automatically when the user has submitted it, consider the possibility that I have sent you an email saying your bank account needs looking at. The email has a link to a page I have made which has an iframe of your bank's site set to fill the entire viewable part of my page. You log in as normal, because you are very trusting. If I had access to the fact that you hit submit on the page, that would imply I also had access to what you submitted or at the very least the URL that the iframe redirected to (which could have a session ID in or all sorts of other data the bank shouldn't include in a URL).
I don't mean to sound preachy at all. You should just consider that in order to know about one event, you often are given access to other data that you ought not have.
I think a slightly less elegant solution to your problem would be to have a link above the iframe that says "Finished" or "Close" that kills the iframe when the user is done with the form. This would not only close the iframe when the user has submitted the form, but also give them a chance to to say "oops! I don't want to fill out this form anyway. Nevermind!" Right now with your desired automatic solution, there is no way to get rid of the iframe unless the user hits submit.
Thank you everybody for your answers. I found a solution that works:
On my server, I tell the form to redirect to the url that created the iframe.
On the site containing the iframe, I add a setInterval function to poll for the current location of the iframe.
Due to JS sandboxing, this poll does not work while the url is foreign (i.e. before my form is submitted). However, once the url is local (i.e. identical to that of the calling page), the url is readable, and the function closes the iframe. This works as soon as the iframe is redirected, I don't even need to wait for the additional pageload.
Thank you very much Greg for helping me :)

Categories

Resources