I got caught in problems with CORS and HTTPS and POST request and just cannot get out of it.
My setup:
I have a web app that runs on HTTPS protocol
I need to make POST request to API on different domain (sailsjs with CORS enabled)
The API is setup to accept both HTTP and HTTPS requests (nginx)
Problems:
On desktop everything works fine if I use HTTPS protocol. If I make call to HTTP, I get error: "Blocked loading mixed active content"
On Mobile I spent days and days trying to make work HTTPS calls, I tried hundereds of ways, to no success. HTTP calls work fine, but again cannot use HTTPS to HTTP.
So basically, on desktop everything works splendid while everything is on https. On mobile it doesn't work. When switching to http target everything brakes because of mixed origin.
More Details
The webapp is using Angular which is making CORS POST HTTPS requests without any problems on all platforms.
The small part that I am trying to make work is using vanilla xhr request:
submit: function(data){
var request = this.createCORSRequest("POST",'https://heregoesthedomain.com');
if (request){
request.onload = function() {
// Success code goes here.
console.log('success');
};
request.onerror = function() {
// Error code goes here.
console.log('error');
};
request.send(JSON.stringify(data));
}
},
createCORSRequest: function(method, url){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// Most browsers.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// IE8 & IE9
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// CORS not supported.
xhr = null;
}
return xhr;
}
Angular seems to be making post requests from HTTPS to HTTPS from domain to domain without a problem across all platforms, while I just cannot seem to make it work in clean JS. I cannot use Angular script, because I need these calls to happen before Angular is initialized.
Update 1
Just to make clear, I didn't post this question after 5 minutes of trying. I have done all kinds of debugging, I have used remote consoles for mobile browser debugging etc etc.
If you ask for the error messages, there simply isn't any. Request returns status:0 and all other XMLHttp values are simply empty. I have read in one of the specs that request get sometime blocked when its been made from origin that is no longer active/doesnt exist, but that is not my case. Simply staying on the same static page.
Since you API works with both types of schemes you could make the requesting URL match the scheme of the page (using a schema less url)
this.createCORSRequest("POST",'//heregoesthedomain.com')
This should solve the
Blocked loading mixed active content
problem.
Also on IE8/IE9 you cannot do normal way any CORS request. You can sort it by using XDomain
Never then less still I will say that for web browser you will get problem with mix content. Only solution is creating special route so you will have http and other calls on https.
If you have Netflix look that they sort it out by playing movie on http because there movie chunks are get by http and session is done by https
Related
How do you get data from a REST API with JavaScript. I have several basic API's that I would like to get data from that don't require any authentication. All of the API's return the data I want back in JSON. For example https://www.codewars.com/api/v1/users/MrAutoIt. I thought this would be a very simple process using xmlhttprequest but it appears the same-origin policy is giving me problems.
I have tried following several tutorials but they don’t seem to work on cross domains or I don’t understand them. I tried to post links to the tutorials but I don't have a high enough reputation on here yet.
If you are trying to access a web service that is not on the same host:port as the webpage that is issuing the request, you will bump into the same origin policy. There are several things you can do, but all of them require the owner of the service to do things for you.
1) Since same origin policy does not impact scripts, allow the service to respond by JSONP instead of JSON; or
2) Send Access-Control-Allow-Origin header in the web service response that grants your webpage access
If you cannot get the service owner to grant you access, you can make a request serverside (e.g. from Node.js or PHP or Rails code) from a server that is under your control, then forward the data to your web page. However, depending on terms of service of the web service, you may be in breach, and you risk them banning your server.
In fact, it depends on what your server REST API supports regarding JSONP or CORS. You also need to understand how CORS works because there are two different cases:
Simple requests. We are in this case if we use HTTP methods GET, HEAD and POST. In the case of POST method, only content types with following values are supported: text/plain, application/x-www-form-urlencoded, multipart/form-data.
Preflighted requests. When you aren't in the case of simple requests, a first request (with HTTP method OPTIONS) is done to check what can be done in the context of cross-domain requests.
That said, you need to add something into your AJAX requests to enable CORS support on the server side. I think about headers like Origin, Access-Control-Request-Headers and Access-Control-Request-Method.
Most of JS libraries / frameworks like Angular support such approach.
With jQuery (see http://api.jquery.com/jquery.ajax/). There are some possible configurations at this level through crossDomain and xhrFields > withCredentials.
With Angular (see How to enable CORS in AngularJs):
angular
.module('mapManagerApp', [ (...) ]
.config(['$httpProvider', function($httpProvider) {
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
If you want to use low-level JS API for AJAX, you need to consider several things:
use XMLHttpRequest in Firefox 3.5+, Safari 4+ & Chrome and XDomainRequest object in IE8+
use xhr.withCredentials to true, if you want to use credentials with AJAX and CORS.
Here are some links that could help you:
Understanding and using CORS: https://templth.wordpress.com/2014/11/12/understanding-and-using-cors/
4 jQuery Cross-Domain AJAX Request methods: http://jquery-howto.blogspot.fr/2013/09/jquery-cross-domain-ajax-request.html#cors (see "1. CORS (Cross-Origin Resource Sharing)")
Unleash your AJAX requests with CORS: http://dev.housetrip.com/2014/04/17/unleash-your-ajax-requests-with-cors/
Using CORS for Cross Domain AJAX requests: http://techblog.constantcontact.com/software-development/using-cors-for-cross-domain-ajax-requests/
Cross origin resource sharing cors AJAX requests between jQuery and Node.js: http://www.bennadel.com/blog/2327-cross-origin-resource-sharing-cors-ajax-requests-between-jquery-and-node-js.htm
Hop it helps you,
Thierry
Here is how you get data.
var request = new XMLHttpRequest();
request.open('GET', 'https://www.codewars.com/api/v1/users/MrAutoIt', true);
request.onload = function() {
if (this.status >= 200 && this.status < 400) {
var resp = this.response; // Success! this is your data.
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
As far as running into same origin policy... You should be requesting from an origin you control, or you can try disabling Chrome's web security, or installing an extension such as Allow-Control-Allow-Origin * to force headers.
For a get method you could have something like this:
#section scripts{
<script type="text/javascript">
$(function()
{
$.getJSON('/api/contact', function(contactsJsonPayload)
{
$(contactsJsonPayload).each(function(i, item)
{
$('#contacts').append('<li>' + item.Name + '</li>');
});
});
});
</script>
}
In this tutorial check the topic: Exercise 3: Consume the Web API from an HTML Client
I have spent hours trying to access a resource from a different domain.
http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/ which is referenced in other SO posts states that by simply using XMLHttpRequest in a browser that supports CORS, CORS policy should be enabled. However I am still getting
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.nczonline.net/. This can be fixed by moving the resource to the same domain or enabling CORS.
When using it in Firefox 34 which according to http://caniuse.com/#feat=cors should be sufficient.
I am trying a simple example from http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/
<script type="text/javascript">
function log(msg){
var output = $('#output');
output.text(output.text() + " | " + msg);
console.log(msg);
}
function createCORSRequest(method, url){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr){
xhr.open(method, url, true);
log("'withCredentials' exist in xhr");
} else if (typeof XDomainRequest != "undefined"){
xhr = new XDomainRequest();
xhr.open(method, url);
log("XDomainRequest is being used");
} else {
xhr = null;
log("xhr is null");
}
return xhr;
}
function main(){
log("Attempting to make CORS request");
var request = createCORSRequest("get", "https://www.nczonline.net/");
if (request){
request.onload = function(){
log("LOADED!");
};
request.send();
}
}
$(window).load(function(){
main();
});
</script>
And I am getting the following output:
Attempting to make CORS request
'withCredentials' exist in xhr
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.nczonline.net/. This can be fixed by moving the resource to the same domain or enabling CORS.
Trying it on fiddle https://jsfiddle.net/zf8ydb9v/ gives same results. Is there another lever somewhere that needs to switched on to be able to use CORS bBesides using XMLHttpRequest?
The same origin policy (which prevents making of CORS requests) is there for your security, not the security of the server: it prevents malicious scripts to access your data on other servers using your cookies.
So, if you want you can still disable it at your own risk, on your browser.
In Chrome/Chromium, if you want to disable the same origin policy you can start it with the --disable-web-security option:
chromium-browser --disable-web-security
Anyway, if you want it to work for your users, they will not able to make CORS requests if they have not disabled this security check in their browsers (which is discouraged if not for testing).
As noted in other answers, some servers can purposely allow this kind of requests if they believe this can be useful and not harmful for their users, and they can do this with the Access-control headers.
Moreover, if you still want to find a way to provide this kind of functionality to the users, you might make a Chrome extension, which is not bound to the same origin policy.
A common solution to this is to make the cross origin request server side, returning the result to your application. You should be careful coding this: passing the url to fetch to the server will easily cause security concerns for your server side software. But if you have to fetch the same url every time, you could hard code it server side, in PHP would look like something like this:
<?php
echo file_get_contents("http://your_cross_request/");
?>
then making an ajax request to this page (which will be from the same origin) will return the content of the remote url.
CORS headers are found in the response sent by the server to your request. If the requested page isn't sending the header, it doesn't matter what you did with the request in a stock browser, you'll get a security error
The relevant CORS headers look like this, the last being the most important one
Access-Control-Allow-Credentials: false
Access-Control-Allow-Methods: GET
Access-Control-Allow-Origin: *
I tried opening "nczonline.net" and when I looked at the response headers I did not see any of these, so the server is not configured to permit being loaded in this way
If you are an administrator of that website, you may want to consider adding the required headers to your responses, perhaps being specific about permitted origins rather than using the wildcard
If you're simply trying to demo your code and want to try it with a third party, load a page which does send these headers e.g. developer.mozilla.org
I'm trying to send an AJAX request from a secure page, but the XMLHttpRequest object doesn't properly resolve the protocol portion of the URL. This behavior is identical in Safari, Chrome, and Canary.
Here's my JavaScript:
function sendGETRequest(url, params, callback) {
"use strict";
var req = new XMLHttpRequest();
req.onreadystatechange = function () {
if (req.readyState === 4) {
if (req.status !== 200) {
callback({ajaxError: true, status: req.status});
} else {
callback(req);
}
}
};
req.open("GET", url + "?" + params, true);
req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
req.send();
}
Here are some different URLs passed to sendGETRequest(), along with their results:
url = "ajax/";
GET https://mydomain/mypage/ajax/?params 404 (NOT FOUND)
The above is the expected behavior: the relative url is correctly resolved with protocol intact.
url = "/ajax/";
The page at https://mydomain/mypage/ displayed insecure content from http://mydomain/ajax/?params.
Here, the realtive url is correctly appended to the domain root, but with the wrong protocol.
url = "https://mydomain/ajax/";
The page at https://mydomain/mypage/ displayed insecure content from http://mydomain/ajax/?params.
Here, the protocol is just ignored.
To be clear, I'm not trying to work around the same origin policy; I want to send an AJAX request from a secure page to a resource with the same (secure) origin. How can I accomplish this simple task?
There is a conversation here about this topic: http://bytes.com/topic/javascript/answers/459071-ajax-https
One of the last posts states "Just to be absolutely unambiguous; XML HTTP requests work over https
exactly as they do over http. If they did not our QA department would
have said something by now as they test over https almost exclusively"
Perhaps the server is not using Https (ssl) at the point where the request is being made: mydomain/ajax/.
This has nothing to do with HTTP and HTTPS. As you mentioned in a comment, the request is never being sent due to same-origin policy. How can the request be using the wrong policy if the request is never sent? What is confusing you is that whatever program/add-on/tool/etc that is generating the error message is showing "HTTP" instead of "HTTPS". The request IS and ALWAYS respects HTTPS when HTTPS is set.
Your real issue is quite simply that you are violating cross-origin policy. See this:
https://developer.mozilla.org/en-US/docs/Same-origin_policy_for_file:_URIs
You cannot go UP the directory tree, only down. In the first example, you are requesting a subfolder. That's fine. In the second and third examples, you are requesting a page from a parent directory (ie, instead of https://mydomain/mypage/ajax/ you are asking for https://mydomain/ajax/. You cannot make a request up a directory tree like that.
Either move your index page up to the root of the domain, or change the same-origin policy header being sent on the files, or make a sub directory on the server handle the request (you can use something like PHP's include to just include the parent file).
This is a bug in WebKit. It's been fixed in Safari 5 for Lion but not Snow Leopard, and it's been fixed in Chrome but not Canary,... helluva a bug.
I tried to use Twitter API to post a tweet using Javascript. Details Below
Base String
POST&http%3A%2F%2Fapi.twitter.com%2F1%2Fstatuses%2Fupdate.json&oauth_consumer_key%3DXXXXXXXXXXX%26oauth_nonce%3D9acc2f75c97622d1d2b4c4fb4124632b1273b0e0%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1305227053%26oauth_token%3D159970118-XXXXXXXXXXXXXXXXXXXXXXX%26oauth_version%3D1.0%26status%3DHello
Header
OAuth
oauth_nonce="9acc2f75c97622d1d2b4c4fb4124632b1273b0e0",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1305227053",
oauth_consumer_key="XXXXXXXXXXXXXXXXX",
oauth_token="159970118-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
oauth_signature="IWuyoPJBrfY03Hg5QJhDRtPoaDs%3D",
oauth_version="1.0"
I used POST method with body "status=Hello"
But i get a INTERNAL SERVER ERROR.. IS there any mistake on my side ?? Thanks in advance.
Javascript code used
h is the header given above
tweet="Hello"
encodeURLall is user defined which is working in all other occasions.
var xhr = new XMLHttpRequest();
xhr.open("POST","http://api.twitter.com/1/statuses/update.json", false);
xhr.setRequestHeader("Authorization",h);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 )
{
console.log("STATUS="+xhr.status);
console.log("RESPONSE="+xhr.responseText);
}
}
xhr.send("status="+encodeURLall(tweet));
}
You cannot access Twitter's site using an XMLHttpRequest, due to Same origin policy. Use JSONP instead or a server-side proxy (call your own server that redirects your request to Twitter).
BTW, what does encodeURLall() do? Shouldn't you just use encodeURIComponent?
Update: To quote Google:
Regular web pages can use the XMLHttpRequest object to send and receive data from remote servers, but they're limited by the same origin policy. Extensions aren't so limited. An extension can talk to remote servers outside of its origin, as long as it first requests cross-origin permissions.
Please read on there to see which settings you should change in order to make this work.
I'm working on a very simple Sidebar Gadget to analyze my router's monthly bandwidth usage and determine how far ahead or behind I am for that month. The data is located in a router-hosted, password protected webpage (I'm using DD-WRT, if it matters). I'd like to pass a page request to the router with Javascript, along with all the authentication information, to retrieve the page all in one go, but I can't seem to find the proper syntax for that. Any ideas?
Here's my code so far:
var ua = navigator.userAgent.toLowerCase();
if (!window.ActiveXObject){
req = new XMLHttpRequest();
}else if (ua.indexOf('msie 5') == -1){
req = new ActiveXObject("Msxml2.XMLHTTP");
}else{
req = new ActiveXObject("Microsoft.XMLHTTP");
}
req.open('GET', 'http://192.168.1.1/Status_Internet.asp', false, "username", "password");
req.send(null);
if(req.status == 200){
dump(req.responseText);
} else{
document.write("Error");
}
document.write("Second Error");
Firebug indicates that it throws an error on req.send(null) - specifically,
Access to restricted URI denied" code: "1012.
It may be because of the same-origin policy, but in that case what can I use instead of an xmlhttpRequest?
It is because of the same-origin policy, the alternative is an iframe but that will not really give you what you wish for.
If it is http-auth you used to be able to request the page with http://username:pass#site but i must admit i haven't tried to use that for a long time, so i don't know if it is still supported.
EDIT:
If this doesn't work, maybe you can use basic http auth as described here: http://en.wikipedia.org/wiki/Basic_access_authentication but this would require you to sue a serverside proxy, since you can't manipulate the request headers from javascript when xhr is not an option.
You need to add a Authorization header to the request. I'm not an AJAX expert, so I'm not sure if you can modify header fields in AJAX requests. If you can't, then you're doomed.
If you can, then this Wikipedia article contains an example what it must look like.
That's a security feature: you see, there are malicious scripts that used a similar technique to hack the routers (who changes their router password anyway? Apparently not Joe X. Schmoe).
Under the Same Origin Policy, AJAX requests are limited to the domain (and port) whence they originated: therefore, from a local page, you can't make a request to 192.168.1.1:80 .
There is a possible workaround - a server-side proxy (e.g. a PHP script that fetches the router pages for you) inside your network.
If the same-origin policy is not the issue, then
load jQuery on your page.
and use jQuery's $.ajax method.
$.ajax({
url: "path/to/your/page.html", // self-explanatory
password:"your password", // a string with your password.
success: function(data){ // on sucsess:
$("someDiv").html(data); // load in the retrived page
}
});
See the jQuery ajax API for details.