I have a Lumen backend and an Angularjs project on the same server without a virtual host. The way I access APIs is simply by the URL like www.example.com/api/public/get_some_data. I want to hide these endpoints from the public but only allow access from the Angularjs.
I tried adding this to the .htaccess in the api/public folder,
Order deny, allow
Deny from all
Allow from 127.0.0.1
But Angular will be denied as well.
I access the endpoint from Angular like this,
function login(user) {
return $http({
method: 'POST',
url: 'api/public/login/user',
data: user,
headers: {'Content-Type': 'application/json'}
}).then(function(response){
console.log(response);
localStorage.setItem('token', response.data.token);
}).catch(dataServiceError);
}
Angular is client side framework. There is no difference for a server if a request comes from Angular application or anywhere else.
Access can be restricted based on some condition that can be satisfied by client side application, like request headers (example).
Security through obscurity is the weakest form of security and shouldn't be relied on. A proper solution in this case is basic authentication or token-based authentication.
Still, if an intruder has access to Angular application, he or she automatically gains access to API endpoints and can extract authentication information from the application.
Related
I have tried all things, use CORS plugin. disable web-security in chrome.
The response is coming in POSTMAN but not able to fetch it in $http.
$http({
url: "https://interview-api-staging.bytemark.co/books",
method: 'GET',
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'OPTIONS,POST,GET,OPTIONS,PUT,DELETE',
'Access-Control-Allow-Headers': 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since'
}
}).then(function(d) {
console.log(d);
});
Client has nothing to do with it. With a CORS header, you're telling the client which other servers do I trust. Those then can share your resources and client won't mind.
For example if you have two domains you tell the client so let your resources be used by your second website, you don't say I trust you as a client.
So you're protecting the server, not client. You don't want AJAX API Endpoints to be accessible by scripts hosted anywhere in the world.
A client has nothing to gain/lose from this. It's only a protection for servers because using AJAX all the URLs are clearly visible to anyone and had it been not for this protection, anybody could go-ahead run their front end using your API, only servers have to lose from this so they get to decide who can use their resources.
source.
As mentioned you don't need to do any cors related stuff in the front-end. Make sure the cors headers are sent from the backend in its response headers.
It is the server that has to protect itself so they have to tell some rules to the client which client will follow. By default, the client will accept everything.
Use CORS in your backend. Otherwise, you can check out Allow-Control-Allow-Origin: * in the Chrome Web Store, use chrome extension.
when you trying to hit through the angular app you need to turn on that extension.
otherwise you need to active CORS in your backend application
I've been looking everywhere but can't seem to find an answer that has been helpful.
I have written an angular app that is trying to pull data from a django RESTful backend that was written by my company. I have a username and password, but I'm not sure how to write the get request to provide the authentication credentials to the backend. I'm also confused about what exactly I'm supposed to provide in the header.
Eventually, we will be communicating using nginx.
What I want
I'm looking for a fix to write in the angular app itself. I'm trying to write the angular app as separate as possible from the django backend. I have already enabled cross origin resource sharing.
This will be a band aid fix just to display data from the backend. It does not need to be permanent by any means.
So far I have tried:
app.factory('mySamples', ['$http', function($http) {
return $http.get('website/api/foo', {
headers: {'username':"foo", 'password': 'bar'}
}).success(function(data) {
return data;
}).error(function(err) {
return err;
});
};
app.factory('mySamples', ['$http', function($http) {
return $http({method: 'GET', url: 'website/api/samples/', headers: {
'user': 'foo', 'auth':'bar'}
});
};
The second factory I wrote returns METHOD: OPTIONS in the networks inspector under returned header. Does anybody have a quick fix just to get data from my api?
EDIT: My django backend doesn't support basic authentication, only session based. How would I edit my get request?
You first need to know what kind of Authentication and Authorization is implemented on the server side i.e. What headers the server looks for authentication/authorization credentials in and what format is expected by the server, then send the credentials under that header key. For example if the sever checks for Authentication credentials in the Authorization header in format username::password then you need to add the headers like
headers: {'Authorization': 'johndoe::password'}
(1) If you are using basic authentication, you can add a basic authentication like so:
app.factory('mySamples', ['$http', function($http) {
var credentials = btoa(username + ':' + authtoken);
var authorization = {
'Authorization': 'Basic ' + credentials
};
return $http({method: 'GET', url: 'website/api/samples/', headers: authorization });
};
If all of your $http calls use this same auth, you can use $http.defaults.headers.common.Authorization
(2) I’m pretty sure nginx does not provide session handling—you’ll have to do that in django.
(3) I don’t typically use sessions with REST since REST is usually done stateless.
OP asked how to enable CORS. Enabling CORS is usually done on the server-side. You can do it in nginx by adding:
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
To the appropriate location block. You can also do this on the django side with middleware pacakges like django-cors-middleware (https://pypi.python.org/pypi/django-cors-middleware) or django-cors-headers (https://pypi.python.org/pypi/django-cors-headers).
I am using a REST API call to query all open issues in the JIRA server. Below is the query:
https://jiraserver/rest/api/2/search?jql=project IN ("Project Name") AND status IN (open)
When I pass the query in Google Chrome advanced REST client, I am able to get a JSON response but when I give this in a HTTP call in Angular.js it returns:
No 'Access-Control-Allow-Origin' header error.
I am new to Angular.js, and I am not able to recognize what is going wrong. Can someone help me out?
Access-Control-Allow-Origin
This comes when the server is configured for not to share data for cross domain requests.
When I pass the query in google chrome advanced rest client , am able to get a json response
Yes, All the rest clients can access data because they are allowed to do so, but for ajax You should enable the CORS to share data cross domain.
Another way is to create proxy
What one can do is, create a proxy at server which can in turn calls the other url and get the data and send it. You can do something like this:
<?php
// suppose this page as "proxy.php"
header('Content-Type: application/json');
$jsonData = json_decode(file_get_contents('https://jiraserver/rest/api/2/search?jql=project'));
echo $jsonData;
?>
Then in the ajax you can use ajax to send a request to this file:
$http({
method: 'POST',
url: '/proxy.php'
}).then(function successCallback(response) {
console.log(response);
}, function errorCallback(response) {
console.log(response);
});
Since JIRA 6.0 you could configure a whitelist for CORS, see JIRA-30371:
CORS has been supported in the JIRA REST API since JIRA 6.0 for JIRA Server. If you are a JIRA Server customer, simply go to the "Whitelist" section of JIRA Administration and add the domains you wish to request resources from. Note: You must have the System Administrator global permission to access this section of JIRA administration.
Unfortunately, this domain whitelist is not available in JIRA Cloud for security reasons. We are currently exploring alternative ways to allow certain requests that would not expose JIRA to this attack vector. I will update this issue as soon as we have more information.
See also: Configuring the Whitelist
Is it possible to use basic auth with the following snippet to make a simple post request to a site running locally?
app.controller('post', function($scope, $http) {
$http.post("http://localhost:8888/angular//wp-json/posts", {'title':'Posting from Angular'})
.success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
document.getElementById("response").innerHTML = "It worked!";
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
document.getElementById("response").innerHTML= "It did not work!";
alert(status)
});
});
When you say basic auth, do you mean HTTP Basic Authentication?
If that's what you mean: then NO. HTTP Basic Authentication requires that your client (in this case, your web browser) needs to know your API keys and be able to send them over the network to your server. Since you're running Angular inside of a web browser, this means that any user visiting your site would theoretically be able to view your API credentials in plain text by inspecting the browser's Javascript console.
This is a HUGE security risk.
What you want to do instead is use a protocol like OAuth2 with the Password Grant (more info here: https://stormpath.com/blog/token-auth-spa/).
OAuth2 allows you to basically do this:
Have a user log into your application with a username/password.
When the login is successful, a token will be returned and stored in a web browser cookie that is HIDDEN FROM JAVASCRIPT.
Then you can use Angular to POST to your API service, as the browser will automatically attach the relevant token API credentials in the HTTP Authorization header automatically.
Your server can then grab the token out of the HTTP Authorization header, and validate the credentials in this way.
This is the only safe way to access an authenticated API service from a browser.
I am very confused. I am trying to use a web service to obtain data. When I put the url into the browser, it works great and returns the json I was expecting.
If angular is a client side framework, why does it not succeed when making the exact same request? The is coming from my browser but the receiving domain still barfs on it.
What am I missing?
Whoever owns the service needs to configure CORS (Cross Origin Resource Sharing), to either allow your particular domain access to the service or to allow all domains to access the service. You then need to configure the correct headers to send your origin and credentials to the origin you are trying to access the service on when making the request so that it can decide if it's gonna let you hit that endpoint or reject the request. Here's the go-to website for an overview and setup guide for CORS: http://enable-cors.org/.
You also need to set the withCredentials flag to true on the http request config object.
Ex.
$http({
url : 'url of service',
method : "POST",
data : {
test : name
},
withCredentials : true,
headers : {
'Content-Type' : 'application/json; charset=utf-8'
}
});
More about the angular configuration for this can be found on the angular docs website for the $http service.