accessing external site gives "mixed content" error with angular $resource - javascript

my server is running over https, but I need to be able to access a resource on an external site (that I have no control over) that is only available via http
I've used the user $resource setup
var tableDefintion = $resource('http://www.externalsite.org/xx/info.php',
{
param: '#data'
}
but, obviously, when I make a resource request I get the dreaded "Mixed Content" message and it will not load
I have tried adding $sceDelegateProvider.resourceUrlWhitelist to the angular config function, but that has made no difference, even when set to ['**']
This resource is being used from within a service - is there anything else I can do to get round this issue ?
thanks

If you are trying to do this by getting the client (browser) to do this request then there is no way round this (MDN) as it's a security risk. However if you have a server why not proxy the request via your server so you can do the TLS termination yourself?

Related

No 'Access-Control-Allow-Origin' header present AngularJS

I am trying to build a quick demo site that I do not have control over the server I am trying to connect to. Here is the code that I am using to build it with AngularJS. I am running the file through a simple Python HTTP Server and viewing it at localhost:8000.
var retrieveAppliances = function () {
console.log('Attempting to retrieve appliance list.');
var requestUrl = '****';
$http({
method: 'GET',
url: requestUrl,
})
.then(function (response) {
console.log(response);
});
};
retrieveAppliances();
I have read multiple places to try switching the method to JSONP but doing so resulted in a parsing error.
While I have considered trying to build a server.js file and running NodeJS with it, I am unsuccessful in learning the basics of making an AJAX request and proxying that to my app.js.
I will greatly appreciate any help that someone may be able to give me, with clear and easy to follow steps.
If you're running an Ajax call to a different origin (e.g. different host, port or protocol) and the server at that origin does not have support for cross origin requests, then you cannot fix that from your client. There is nothing you can do from the client.
If the server supported JSONP, you could use that, but that also requires specific server support.
The only solutions from a browser web page are:
CORS support on the target server.
JSONP (also requires support on the target server).
Set up your own server that you do have access to (either on your existing page domain or with CORS) and then have that server get the file/data for you and proxy it back to you. You can either write your own proxy or deploy a pre-built proxy.
Find some existing third party proxy service that you can use.
If you're interested in making your own node.js proxy, you can see a simple example here: How to create a simple http proxy in node.js?.

How to use jQuery GET on HTTP (non-secure) server?

I'm getting this error when I try to use $.get on a non-secure site (ie. http, not https):
jquery.min.js:4 Mixed Content: The page at '...' was loaded over HTTPS, but requested an insecure script 'http://api.openweathermap.org/data/2.5/weather?lat=50&lon=2?callback=jQuery...'. This request has been blocked; the content must be served over HTTPS.
I've been trying to think of work-around solutions to this. The problem is a fixed one, since the server is hosted by OpenWeather.org and it's a non-secure site (ie. http, not https).
This is my request code:
$.get("https://api.openweathermap.org/data/2.5/weather?lat=" + latitude + "&lon=" + longitude + "&APPID=123456", function(data) {
tempC = data.weather.main.temp / 10; // OpenWeather API returns Celsius * 10
rain = data.rain["3h"];
clouds = data.clouds.all;
});
Simply changing the request URL to https://api.openweathermap.org... doesn't work, of course. Tried it and didn't work.
The only solution I can think of right now is to find another weather API that is free to use for my project, but I'd like to know if there's a way to still use OpenWeathermap's API, given that it's http. Curious to know this because it seems quite wasteful to have to dismiss certain APIs just because it's http and not https.
Found another post on SO about the same "mixed content" issue. It's helpful and points to many other resources to solve the problem.
The asker ended up dropping openweathermap API (because it's served over HTTP) and using forecast.io's API instead (served over HTTPS while still free).
Using Open Weather Map which is HTTP only through an HTTPS website and NOT get mixed content warning
so, the Problem is, that you run your code on a HTTPS site(JSFiddle and Coodepen). Your browser will not allow HTTP-Connections on a HTTPS site for security-reasons. You can solve that issue by either forcing HTTP on the page where you run your code(try to run a code from a local file or localhost) or you could create a HTTPS -> HTTP forwarding on your server, that would receive a HTTPS request from your code and send a HTTP-request to API.
I would suggest first try to run from a localhost or local file(not sure if every browser will allow AJAX from a local file, but you can try before setting up localhost), that should work for you. If you just want to test the API you can simple copy the URL of the GET-request into you browser tab and execute it.

Gracefully Handling 401 Not Authorized with Angularjs $http

I am currently working on an problem with a login page for an AngularJS app. The login page uses the $http service to submit the username and password using Basic authentication (Authorization: Basic (username and password in base 64)) to a Web service that may or may not be running on the same server that the webapp is hosted on. If authentication succeeds, the server returns a response with status 200 OK; otherwise, it returns a 401 Not Authorized. We have an error function to gracefully handle this error condition, but before it is even called, the browser by default shows a modal dialog for the user to enter his or her username and password. How can I prevent this?
I've looked at several sources, including the W3 standards for XHR.send(), for help, and my findings show that in Firefox and Chrome, the browser dialog pops up after a 401 response to an XHR call when all of the following are true:
1) The request is "same-origin" (which it is in the cases where the web service is running on the same server that serves the webapp)
2) The response includes the header WWW-Authenticate: Basic [some realm] or WWW-Authenticate: Digest [some realm] (our web service returns the former)
3) The request was not made by specifically setting a username and password in the XHR object whose send() method was called.
I found a test site (which SO won't let me link to) that exhibits the desired behavior for 401 responses (no modal login box). It meets the first two conditions but avoids meeting the third, apparently because it sets the XHR object's username and password by sending them as arguments #4 and 5 to its open() function. I'm not sure if there's any other way to set these properties of the XHR object, since I can't even find them by inspecting the XHR object in a browser's JavaScript debugger.
The problem is that our site's login service doesn't itself call XmlHttpRequest.open() to pass the username and password; instead, it creates the Authorization header itself and passes it in the headers collection of a params object to $http. By inspecting the source of angular.js, I found that $http then proceeds to call open() with only three parameters.
Does Angular provide a way to have $http call the 5-parameter overload of open(), or otherwise prevent this login dialog from showing up? If not, I can only think of a few workarounds:
1) Somehow decorate $http to enforce calling the 5-parameter overload of open() if a username and password are provided
2) Somehow use $httpBackend to achieve the same as #1 (though the documentation discourages developers from using $httpBackend so I'm not sure if this is a good idea or even possible)
3) Ignore $http and have my login service create and send the XHR itself
4) Alter the server so it doesn't return the WWW-Authenticate: Basic header (least desirable)
Is there a well-known or "right" way to work around this problem?
The issues you are facing is due to the first reason you have specified
1) The request is "same-origin" (which it is in the cases where the web service is running on the same server that serves the webapp).
solution
Either add access-control-allow-origin header to your backend service in order to acccept calls from different origin.
or
if you are in development phase and later your frontend and service are anyway going to be in same origin,then use https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en extension ,
this will allow you to override chrome cross origin policy (this is just for development,its a workaround).
or
Open chrome with web security disabled by opening chrome from command prompt
chrome.exe --user-data-dir="C:/Chrome dev session" --disable-web-security

Cross-Origin Resource Sharing from browser-hosted JavaScript app to custom server

I am looking for a way to allow browser-hosted JS app to make requests to server running on different port and, possibly, different machine than that which is serving up JS app in the first place.
I am serving a simple JavaScript (HTML5) app from my Mac OS X Apache web server. I would like to be able to run this app in as many browsers as possible across Windows, Android and OS X. But I would settle for one on each.
My JavaScript app uses XMLHttpRequest to make requests of a minimal custom server that returns JSON.
So, for example, my JS app is accessible at http://10.0.1.3/poc/dashboard.html
and my custom server is running on same machine, listening on port 49379 ... a request like this http://10.0.1.3:49379/find?name=Fred would return a set of tuples where 'name' equals 'Fred'.
If I enter this request directly into navigation toolbar, then I get desired result.
If I make same request within JS, I get a couple of errors.
var theXHR = new XMLHttpRequest();
theXHR.onreadystatechange = onReadyStateHandler;
theXHR.open("GET", "http://" + ipAddress + ":49379/find?name=Fred", true);
theXHR.setRequestHeader("User-Agent", "XMLHTTP/1.0");
theXHR.send(null);
I get these two errors:
Refused to set unsafe header "User-Agent"
XMLHttpRequest cannot load http://10.0.1.3:49379/find?name=Fred.
Origin http://10.0.1.3 is not allowed by
Access-Control-Allow-Origin.
I have control over Apache server, JavaScript and custom server. This is just a proof of concept piece that will be demoed on isolated networks. So, I am not concerned with security issues.
Also, I am running in Chrome, Firefox, Safari. All of these appear to use the XMLHttpRequest2 object.
I have found the way to get around CORS is to use jsonp - which is json with a callback function - I've never used it with XMLHttpRequest, but it works with jQuery ajax functions like $.getJSON. In your url query string simply add the parameter jsoncallback=? and voila, no more CORS problems. $.getJSON dynamically assigns its success parameter to the callback function.

How to POST data to an HTTP page from an HTTPS page

I know this is a long shot, but I figured I'd ask the question anyway.
I have an HTTPS page and am dynamically creating a form. I want to POST the form to an HTTP page. Is this possible without the browser popping up a warning? When I do this on IE8, I get the following message:
Do you want to view only the webpage content that was delivered securely?
Essentially, I'm asking about the inverse of question 1554237.
Sadly, I know of absolutely no way to not get warned when posting from HTTPS to HTTP. If you serve the form securely, the browser expects to submit the data securely as well. It would surprise the user if anything else was possible.
Nope, can't be done. Our good friend IE will always pop up that warning.
There is a way to do this if you write a back-end service of your own. So lets say you want to post an HTTP request to s1 using your front-end service fs1.
If you use Spring, you can use an ajax call from fs1 to a 'uri' that is recognized by your spring back-end, say bs1. Now, the service bs1 can make the call to the s1.
Pictorial representation here: http://i.stack.imgur.com/2lTxL.png
code:
$.ajax
({
type: "POST",
uri:/json/<methodName>
data: $('#Form').serialize(),
success: function(response)
{
//handle success here
},
error: function (errorResponse)
{
//handle failure here
}
})
You can solve this by either acting as a proxy for the form destination yourself (i.e. let the form submit to your server which in turn fires a normal HTTP request and returns the response), or to let access the page with the form by HTTP only.
If you don't need to actually redirect to the insecure page, you can provide a web service (authenticated) that fires off the request for you and returns the data.
For example:
From the authenticated page, you call doInsecure.action which you create as a web service over https. doInsecure.action then makes a manual POST request to the insecure page and outputs the response data.
You should be able to do this with the opensource project Forge, but it sounds like overkill. The Forge project provides a JavaScript interface (and XmlHttpRequest wrapper) that can do cross-domain requests. The underlying implementation uses Flash to enable cross-domain (including http <=> https) communication.
http://github.com/digitalbazaar/forge/blob/master/README
So you would load the Forge JavaScript and swf from your server over https and then do a Forge-based XmlHttpRequest over http to do the POST. This would save you from having to do any proxy work on the server, but again, it may be more work than just supporting the POST over https. Also, the assumption here is that there's nothing confidential in the form that is being posted.

Categories

Resources