Cross domain javascript form filling, reverse proxy - javascript

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?

Related

How to detect if a re-Captcha site key is valid via javascript?

I'm attempting to detect the 'Invalid site key' error for googles re-Captcha via javascript so the error can be reported to the server for further handling. I'm using the explicit rendering mode and calling the api function grecaptcha.render('iframeid', {'site-key':'xxx'});although this function doesn't return any error response or throw an exception even if it loads the following:
I can't simply read the loaded error text either as it's loaded in an iframe on a different domain. Is there anyway to detect an invalid site key automatically, either via javascript or server side?
Edit
Final solution was to load a test page with phantomjs and parse the html of the recaptcha
Google does not provide methods to verify site key, neither you can hack/access reCaptcha html code by JS since the reCapthca is in an iframe and frame's code is not programmatically accessible client-side.
Its a common mistake to forget to update the allowable domains in the dashboard when pushing a new site live.
Since you manage multiple domains I'd recommend you to use one site key for all of the domains you use. Use secure token for that.
Hack
Another option might be that you develop a script that will visit site(s) of interest, make screenshot/snap of loaded reCaptcha, apply OCR (eg. using this) and return a result if site key is valid or not.
As Google does not provide an official way to check this, I've just implemented a workaround performing a GET request on Google's Recaptcha URL. I've made using PHP, but it's not hard to adapt the solution for JavaScript, although it can end on a Cross-Origin error due to Same Origin Policy. So if someone tests this solution using JavaScript, let us know how it goes (and if it does not work, it's always possible to run an AJAX to your own server and check the validity directly from your server).
Besides that, in my case, I'm using Invisible ReCaptcha v2, but I think this approach can be used for other Recaptchas as well.
First, you should mount your URL. I couldn't find a way to determine this "co" param, and I don't know what it means. But it looks like different values are all accepted on different sites. You can look for this value by adding the Recaptcha code on your page (no matter if it's with valid keys or not) and then checking the src param on the generated <iframe>.
$recaptcha_url = sprintf(
'https://www.google.com/recaptcha/api2/anchor?ar=1&k=%s&co=%s&hl=%s&size=%s',
RECAPTCHA_SITE_KEY,
'<co_param_value>',
'en-US',
'invisible'
);
on JavaScript it would be something like this:
recaptcha_url = 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=' + RECAPTCHA_SITE_KEY + ' &co=' + CO_VALUE + '&hl=en-US&size=invisible';
If you are not using Invisible Recaptcha, the size param must be different. But you can also omit it because, at least in my testing, it was not necessary for checking if the Site Key is valid (the same for the language param hl).
Then, you perform a GET request on this URL. On PHP, you can use cURL. If it's Wordpress, you can use wp_remote_get. On JavaScript (jQuery, actually), you can use $.get.
$.get( recaptcha_url, function(data, status){ ... });
Finally, you check if the response body has the string 'Recaptcha.anchor.ErrorMain.init'. This means when the Recaptcha Site Key is not valid for the current domain, Google processes the error, and this string appears on the response body (actually, any ReCaptcha error would result on this string, so remember this is a workaround).
If you are using Wordpress, you can do it with wp_remote_retrieve_body. Something like this:
$response = wp_remote_get( $recaptcha_url );
$response_body = wp_remote_retrieve_body( $response );
if( strpos( $response_body, 'recaptcha.anchor.ErrorMain.init' ) !== false ) {
// Site is not valid for current Recaptcha Keys
}
On JavaScript, I think you can check the data variable received on $.get.
Unfortunately, this is not a strong solution. Google can change both the request and the response, and this could break the implementation. But there is nothing we can do about it as there isn't an official call to check the keys.

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).

Sending Post Data to remote site and displaying the results

I've read quite a few posts here asking roughly the same thing, but usually the person asking has access to the remote site and can use the methods available to achieve this. My situation is a bit different, and I just wanted to see if it was possible before spending time and effort trying to get it to work.
The site that I am trying to access is remote, I have no access to it in anyway, and it's only accessible from a computer logged into OpenVPN.
The tool that I am writing is trying to get the results of a form submit from the remote site. I don't want to parse the results or modify it in anyway. I just want to display the page with the Post Data sent. The remote site uses AJAX for the form submit.
It's code is as such:
<form name="MyForm" action="response_normal.php" method="post" onsubmit="xmlhttpPost('response_ajax_v2.php', 'MyForm', 'response', '<img src=\'pleasewait.gif\'>'); return false;">
Upon submitting on that page, three values are sent:
site : radio1
search : 000000000000
submit : Search Site
Is it possible at all for me to simply send that post data to the page and display it? I am hoping to do this in an iframe - since I can't do it server side due to VPN restrictions.
Since the computer you're accessing your offsite server from is on the VPN that has access to the remote system (and assuming this remote system is under your control), you could have the offsite server return some JavaScript that AJAX-pulls the data–in this case, a full HTML page–it needs from the remote system using a JSONP-like strategy.
I have used this technique for some small projects in the past.
From there, you are free to do with the data what you will–modify it, return it as is, or otherwise.
Personally, I would avoid the use of frames if possible. Of course, when strapped for time, nothing is off limits ;)
However, if the remote system IS NOT under your control (and they don't have a kickass CORS cross-access policy), your only option is, as you said in the body of your question, frames. Here is an example:
<!-- If the remote system is NOT under your control, it CANNOT respond with the X-Frame-Options header set to SAMEORIGIN or DENY! -->
<iframe id="inlineframe" src="http://www.randomwebsite.com" frameborder="0" scrolling="auto" width="800" height="300" marginwidth="5" marginheight="5" ></iframe>
//Depending on the JS you put here, you may get some "unsafe Javascript" warnings from certain browsers
~function()
{
var frame = document.getElementById('inlineframe'),
ref = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument;
// ref is now a reference to the document of the content within the iframe
// You can now do your getElementById/getElementByTagName etc. and otherwise
// manipulate the response as you please.
console.log(ref);
}();
A working example can be found here: http://jsfiddle.net/FTudJ/
The contents of the iframe should be the submitted results of the remote page, or whatever the remote server responds with. If you're not looking to modify anything, then you don't even need the Javascript component.
The key will be the URL you specify as the source of the iframe. Now, if the remote system doesn't support GET requests for form submissions (in your example code I see a "POST" method), coupled with the fact that you have no control over it and your offsite system can't access it in any way, your only other options are:
Instead of supplying the form's submission URL directly, simply supply the form's typical access URL to the iframe. From there, use JavaScript to populate the form with the necessary values, and then submit the form within the iframe as if you were the user. From there, you can scrape the results back into JavaScript or simply display them as is.
Find a way to get your offsite server into the VPN network so that it may communicate with the remote system on your behalf. Of course, if that were easy, I guess you would have done that first!
Redirect your users to the remote site–possibly using a frameset + banner frame like Google used to do, let them do what they need to do there, and then tell them to come back when they're finished.
--
I see that you're using PHP. As long as the server that is executing the PHP has access to the VPN that has access to this remote system–all over traditional HTTP–a simple curl call from the server-side should suffice, as you can use AJAX to pass through the results to the client.
These links may be of some assistance:
http://php.net/manual/en/book.curl.php
What is cURL in PHP?
http://php.net/manual/en/curl.examples-basic.php
Post data and retrieve the response using PHP Curl?

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 :)

Cross domain Ajax request from within js file

Here's the problem:
1.) We have page here... www.blah.com/mypage.html
2.) That page requests a js file www.foo.com like this...
<script type="text/javascript" src="http://www.foo.com/jsfile.js" />
3.) "jsfile.js" uses Prototype to make an Ajax request back to www.foo.com.
4.) The ajax request calls www.foo.com/blah.html. The callback function gets the html response and throws it into a div.
This doesn't seem to work though, I guess it is XSS. Is that correct?
If so, how can I solve this problem? Is there any other way to get my html from www.foo.com to www.blah.com on the client without using an iframe?
It is XSS and it is forbidden. You should really not do things that way.
If you really need to, make your AJAX code call the local code (PHP, ASP, whatever) on blah.com and make it behave like client and fetch whatever you need from foo.com and return that back to the client. If you use PHP, you can do this with fopen('www.foo.com/blah.html', 'r') and then reading the contents as if it was a regular file.
Of course, allow_remote_url_fopen (or whatever it is called exactly) needs to be enabled in your php.ini.
There is a w3c proposal for allowing sites to specify other sites which are allowed to make cross site queries to them. (Wikipedia might want to allow all request for articles, say, but google mail wouldn't want to allow requests - since this might allow any website open when you are logged into google mail to read your mail).
This might be available at some point in the future.
As mentioned above JSONP is a way around this. However, the site that you are requesting the data from needs to support JSONP in order for you to use on the client. (JSONP essentially injects a script tag into the page, and provides a callback function that should be called with the results)
If the site you are making a request to does not support JSONP you will have to proxy the request on your server. As mentioned above you can do this on your own server or what I have done in the past is use a http://www.jsonpit.com, which will proxy the request for you.
One option is to implement a proxy page which takes the needed url as a parameter. e.g. http://blah.com/proxy?uri=http://foo.com/actualRequest
JSONP was partially designed to get around the problem you are having
http://ajaxian.com/archives/jsonp-json-with-padding
JQuery has it in their $.getJSON method
http://docs.jquery.com/Ajax/jQuery.getJSON
The method shown above could become a large security hole.
Suggest you verify the site name against a white list and build the actual URI being proxied on the server side.
For cross domain hits this is a good working example and now is considered as some what "standard" http://www.xml.com/pub/a/2005/12/21/json-dynamic-script-tag.html.
there are other ways as well, for eg injecting iframes with document.domain altered
http://fettig.net/weblog/2005/11/28/how-to-make-xmlhttprequest-connections-to-another-server-in-your-domain/
I still agre that the easy way is calling a proxy in same domain but then it's not truly client side WS call.

Categories

Resources