Protect PHP endpoints called by AJAX - javascript

My app consists of several PHP endpoints which are accessible via AJAX. The problem is they are also accessible via anyone who makes an HTTP request to the same endpoint. I can add checks for HTTP_X_REQUESTED_WITH and HTTP_REFERER as specified in this answer, but these can be spoofed. I could add a secret key that needs to be posted with the request, but anyone viewing the javascript and/or the console would be able to see this key. What is the solution here?

People often think that because they're using Ajax requests regular sessions don't work. They do.
If you have an endpoint to delete something from the database that's visible in the source code, such as:
example.com/user/1/delete
You can protect this request from non authenticated users the same way you would when using a non Ajax HTTP request in the browser. Using sessions. If the user has the privileges to remove users, this route will work, otherwise return an error (or do nothing).
You can also protect an API using OAuth. There's a great document here that explains how it works: http://tatiyants.com/using-oauth-to-protect-internal-rest-api/

Most of the answers are not helpful if you have your app and your api on separate domains for example app.example.com and api.example.com - in that case sessions won't work and you would have to turn to OAuth which is quite a big hammer for such a simple problem.
Here is what I would do:
I assume you have users in a database and a unique identifier like user_id=12345. I also assume that you have your Jobs in a Database and they also have unique ID's like job_id=6789.
First on app.example.com you encrypt both IDs with something fast and easy like Blowfish:
$secret_uid = mcrypt_encrypt(MCRYPT_BLOWFISH, "your_secret", strval($user_id));
$secret_jid = mcrypt_encrypt(MCRYPT_BLOWFISH, "your_secret", strval($job_id));
I assume your endpoint would work somewhat like this:
api.example.com/jobs/delete/<job_id>/<user_id>
so now from Ajax you call that endpoint, but instead of calling with plain IDs
api.example.com/jobs/delete/6789/12345
you call it with the encrypted IDs:
api.example.com/jobs/delete/6A73D5B557C622B3/57F064C07F83644F
On the API side of your software you decrypt the parameters:
$jid = mcrypt_decrypt(MCRYPT_BLOWFISH, "your_secret", <param_1>);
$uid = mcrypt_decrypt(MCRYPT_BLOWFISH, "your_secret", <param_2>);
Now you can search your db for uid and jid and perform whichever task you were planning to do. Make sure that a user can only delete his own jobs of course.
I admit this is not a 100% solution, but it leaves an attacker with a lot of guess work - he would have to guess the user_id and a matching job_id, the encryption algo and your secret. It does not protect against running millions of brute force attempts to guess a matching pair, but it put's the odds in your favor (and you should have some sort of quota limitation protection of your endpoints anyway).
Good luck!

There isn't one. If you give someone some data, then they can process it in whatever way they like. You can't control what happens to it after it leaves your server.
Likewise, you can't control what data they send to the endpoint.

it is very important for a developer to put authentication for API or web services. dchacke and BugHunterUK has given perfect answers, I just want show you simple code I use to make very simple and easy to use authentication.
Adding Session for the authentication
you can add session, and session timeout for your APIs so, only your app can use this, you can start session when front page of your app is loaded, you can set timeouts and also restrict the different service for different users by sessions.
General Idea how to do that
<?php
if(!empty($_SESSION['api_session']) && $_SESSION['api_session'] == 'usertype'){
//usertype comprise of what access you want to give
//guest, registered user, stack holder, admin etc.
...
header('Content-Type:application/json;');
echo json_encode($output);
}

Related

Fastest redirects Javascript

My main function is I am creating a link-shortening app. When someone entered a long URL, it will give a short URL. If the user clicked on the short link it will search for the long URL on the DB and redirect it to the long URL.
Meantime I want to get the click count and clicked user's OS.
I am currently using current code :
app.get('/:shortUrl', async (req, res) => {
const shortUrl = await ShortUrl.findOne({short: req.params.shortUrl})
if (shortUrl == null) return res.sendStatus(404)
res.redirect(shortUrl.full)
})
findOne is finding the Long URL on the database using ShortID. I used mongoDB here
My questions are :
Are there multiple redirect methods in JS?
Is this method work if there is a high load?
Any other methods I can use to achieve the same result?
What other facts that matter on redirect time
What is 'No Redirection Tracking'?
This is a really long question, Thanks to those who invested their time in this.
Your code is ok, the only limitation is where you run it and mongodb.
I have created apps that are analytics tracker, handling billion rows per day.
I suggest you run your node code using AWS Beanstalk APP. It has low latency and scales on your needs.
And you need to put redis between your request and mongodb, you will call mongodb only if your data is not yet in redis. Mongodb has more read limitations than a straight redis instance.
Are there multiple redirect methods in JS?
First off, there are no redirect methods in Javascript. res.redirect() is a feature of the Express http framework that runs in nodejs. This is the only method built into Express, though all a redirect response consists of is a 3xx (often 302) http response status and setting the Location header to the redirect location. You can manually code that just as well as you can use res.redirect() in Express.
You can look at the res.redirect() code in Express here.
The main things it does are set the location header with this:
this.location(address)
And set the http status (which defaults to 302) with this:
this.statusCode = status;
Then, the rest of the code has to do with handling variable arguments, handling an older design for the API and sending a body in either plain text or html (neither of which is required).
Is this method work if there is a high load?
res.redirect() works just fine at a high load. The bottleneck in your code is probably this line of code:
const shortUrl = await ShortUrl.findOne({short: req.params.shortUrl})
And, how high a scale that goes to depends upon a whole bunch of things about your database, configuration, hardware, setup, etc... You should probably just test how many request/sec of this kind your current database can handle.
Any other methods I can use to achieve the same result?
Sure there are. But, you will have to use some data store to look up the shortUrl to find the long url and you will have to create a 302 response somehow. As said earlier, the scale you can achieve will depend entirely upon your database.
What other facts that matter on redirect time
This is pretty much covered above (hint, its all about the database).
What is 'No Redirection Tracking'?
You can read about it here on MDN.

Safe to call WooCommerce, WordPress and CoCart endpoints in frontend? I need your opinion

Question
I got a question about security. I am building a mobile webshop in Flutter. Is it bad to make those API calls in the frontend? Should I make a separate backend for it in Node for example?
I have also read that you can 'create' your own endpoints in WordPress with PHP. What about that? Does that make it any safer or not?
What endpoints do I use?
There is an existing WooCommerce API to retrieve products, get categories, and create orders on the WooCommerce API. On the CoCart API, you can retrieve the cart, add to the cart, delete the cart, etc...
For the Mollie payment APIs, I think it is better to make a backend.
My take on it
I think it is fine to call those endpoints in the front end. I have seen Flutter packages for WooCommerce to call those endpoints. Yes, I do send the basic auth in the headers... so I am not sure how 'dangerous' that is.
But on the other side. What can the 'hacker' do? They can see all the products, that is fine I guess. I am not sure if they can create orders... They cannot steal money at least :)
Reference code
For reference, here is a piece of code when calling an endpoint:
Future<Product> getProductById(int productId) async {
String basicAuth =
'Basic ' + base64Encode(utf8.encode('$username:$password'));
print(basicAuth);
var response = await http.get(
Uri.parse(
'https://websitename/wp-json/wc/v3/products/${productId}'),
headers: <String, String>{'Authorization': basicAuth});
if (response.statusCode == 200) {
return Product.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed');
}
}
Let me know your opinion!
When talking about security main question is what goes over the network request. If your username & password from code above is something to keep secret, that can't be on client side.
If you sent code to user, user got it and can check what's happening while tracing network requests.
You can always skip the UI, debug network request and take all the details that were sent over that request and send those requests with cURL or anything else. Yet client must authenticate somehow, and that's a wide topic from "unlisted" URLs where you just need to have exact "random id" to get to the resource (e.g. youtube's or many file sharing services use that as "unlisted" link, which means this won't be in search results but if you have exact link, you will get into the resource) to oAuth2, which you can learn more about here and
you could check this post too which covers several methods of token-based authentication.

How to make sure that only a specific domain can query from your REST api?

I have an app that has a REST api. I want it so that the only requests that can be made to the REST api are ones originating from the app itself. How can I do that?
I am using a node.js+express server too.
EDIT: the app is fully a public web app.
Simply define the header in your request, what this does is, it allows requests only from a certain domain, and instantly rejects any other domain.
response.set('Access-Control-Allow-Origin', 'domain.tld');
EDIT: IF you're really keen against web scraping stuff, you could make a function to double check client's origin.
function checkOrigin (origin) {
if (origin === "your.domain.tld") {
return true;
} else {
return false;
}
}
/* Handling it in response */
if (checkOrigin(response.headers.origin)) {
// Let client get the thing from API
} else {
response.write("Send them error that they're not allowed to use the API");
response.end();
}
Above example should work for the default HTTP/HTTPS module, and should also work for Express, if I'm not mistaken.
EDIT 2: To back my claim up that it should also work for Express, I found this quotation at their documentation;
The req (request) and res (response) are the exact same objects that Node provides, so you can invoke req.pipe(), req.on('data', callback), and anything else you would do without Express involved.
I would recommend using an API key from the client. CORS filters are too easy to circumvent.
A simple approach for securing a How to implement a secure REST API with node.js
Overview from above post:
Because users can CREATE resources (aka POST/PUT actions) you need to secure your api. You can use oauth or you can build your own solution but keep in mind that all the solutions can be broken if the password it's really easy to discover. The basic idea is to authenticate users using the username, password and a token, aka the apitoken. This apitoken can be generated using node-uuid and the password can be hashed using pbkdf2
Then, you need to save the session somewhere. If you save it in memory in a plain object, if you kill the server and reboot it again the session will be destroyed. Also, this is not scalable. If you use haproxy to load balance between machines or if you simply use workers, this session state will be stored in a single process so if the same user is redirected to another process/machine it will need to authenticate again. Therefore you need to store the session in a common place. This is typically done using redis.
When the user is authenticated (username+password+apitoken) generate another token for the session, aka accesstoken. Again, with node-uuid. Send to the user the accesstoken and the userid. The userid (key) and the accesstoken (value) are stored in redis with and expire time, e.g. 1h.
Now, every time the user does any operation using the rest api it will need to send the userid and the accesstoken.

Securing REST API calls with client-side token

I have a node.js REST API and I want to restrict POST/PUT/DELETE calls to a predefined list of "sources" (web applications which I do not own the code).
The only way I see to achieve this is to put a token on the client-side (something like Google Analytics in JS files) but I have no idea how to secure this since the token will be accessible in the static files.
What strategy should I use ? JWT and OAuth2 seem not indicated since it requires first user authentication, but what I want to authenticate is not user but webapps.
Your question is slightly unclear. You could mean either (a) that you want to strongly encourage the user to use the app and prevent other code from maliciously making your user perform an action, or (b) that you want to absolutely prevent your user from using other code to access your server.
The first option is possible, and indeed a very good idea. The second is impossible, based on the way the Internet works.
First, the impossibility. Essentially, client-side code is there to make life easier for your client. The real work will always be done on the server side -- even if this only means validating data and storing it in the database. Your client will always be able to see all the HTTP requests that they send: that's the way HTTP works. You can't hide the information from them. Even if you generate tokens dynamically (see below), you can't prevent them from using them elsewhere. They can always build a custom HTTP request, which means ultimately that they can, if they really, really want, abandon your app altogether. Think of your client-side code as merely making it easier for them to perform HTTP requests and abandon any idea of preventing them "doing it wrong"!
The much better option is CSRF protection, which gives the best possible protection to both your server and the client. This means sending a generated token to your client when they first log on and verifying it (either by looking it up or decrypting it) when they send it on every request. This is the basis of JWT, which is a beautiful implementation of a fairly old system of verification.
In the end your API is public, since any random website visitor will have to be able to interact with the API. Even if you use tokens to restrict access somewhat, those tokens by definition will have to be public as well. Even regularly expiring and renewing the tokens (e.g. through a backend API, or by including a nonce algorithm) won't help, since those new tokens will again be publicly visible on the 3rd party's website where anyone can fetch one.
CSRF protection can help a little to avoid cross-site abuse within browsers, but is ultimately pointless for the purpose of preventing someone to write an API scraper or such.
The best you can do is use the tokens to identify individual site owners you granted access to, vigilantly monitor your API use, invalidate tokens when you think you're seeing them abused and contact the site owners about securing their tokens better somehow (which they'll have the same problem doing, but at least you have someone to blame cough cough).
You can use hmac to secure this :
Each client has a unique couple of key public/private (for example "public" and "private").
When client send request, he has to send a nonce + his user public key + the hmac of nonce+public key with his private key.
When server handle request, the server retrieve the client according to his public key, get the secret key of the user, then verify the signature.
Client, sample call on /api
var nonce = "randomstring";
var pk = "aaa";
var sk = "bbb";
var string = "pk="+pk+"&nonce="+nonce;
var crypto = require('crypto');
var hmac = crypto.createHmac('sha512', sk).update(string).digest('hex');
// send this payload in your request in get, put, post, ....
var payload = string+"&hmac="+hmac;
request.post({uri:"website.com/api?"+payload}, ....
And
Server side, security check
var nonce = req.query.nonce;
var pk = req.query.pk;
var hmac = req.query.hmac;
// retrieve user and his sk according to pk
var sk = getUser(pk).sk
// rebuild payload string
var string = "pk="+pk+"&nonce="+nonce;
var crypto = require('crypto');
var hmac_check = crypto.createHmac('sha512', sk).update(string).digest('hex');
if(hmac_check === hmac) { // request valid }else{ // invalid request }

Publish data from browser app without writing my own server

I need users to be able to post data from a single page browser application (SPA) to me, but I can't put server-side code on the host.
Is there a web service that I can use for this? I looked at Amazon SQS (simple queue service) but I can't call their REST APIs from within the browser due to cross origin policy.
I favour ease of development over robustness right now, so even just receiving an email would be fine. I'm not sure that the site is even going to catch on. If it does, then I'll develop a server-side component and move hosts.
Not only there are Web Services, but nowadays there are robust systems that provide a way to server-side some logic on your applications. They are called BaaS or Backend as a Service providers, usually to provide some backbone to your front end applications.
Although they have multiple uses, I'm going to list the most common in my opinion:
For mobile applications - Instead of having to learn an API for each device you code to, you can use an standard platform to store logic and data for your application.
For prototyping - If you want to create a slick application, but you don't want to code all the backend logic for the data -less dealing with all the operations and system administration that represents-, through a BaaS provider you only need good Front End skills to code the simplest CRUD applications you can imagine. Some BaaS even allow you to bind some Reduce algorithms to calls your perform to their API.
For web applications - When PaaS (Platform as a Service) came to town to ease the job for Backend End developers in order to avoid the hassle of System Administration and Operations, it was just logic that the same was going to happen to the Backend. There are many clones that showcase the real power of this strategy.
All of this is amazing, but I have yet to mention any of them. I'm going to list the ones that I know the most and have actually used in projects. There are probably many, but as far as I know, this one have satisfied most of my news, whether it's any of the previously ones mentioned.
Parse.com
Parse's most outstanding features target mobile devices; however, nowadays Parse contains an incredible amount of API's that allows you to use it as full feature backend service for Javascript, Android and even Windows 8 applications (Windows 8 SDK was introduced a few months ago this year).
How does a Parse code looks in Javascript?
Parse works through classes and objects (ain't that beautiful?), so you first create a specific class (can be done through Javascript, REST or even the Data Browser manager) and then you add objects to specific classes.
First, add up Parse as a script tag in javascript:
<script type="text/javascript" src="http://www.parsecdn.com/js/parse-1.1.15.min.js"></script>
Then, through a given Application ID and a Javascript Key, initialize Parse.
Parse.initialize("APPLICATION_ID", "JAVASCRIPT_KEY");
From there, it's all object manipulation
var Person = Parse.Object.extend("Person"); //Person is a class *cof* uppercase *cof*
var personObject = new Person();
personObject.save({name: "John"}, {
success: function(object) {
console.log("The object with the data "+ JSON.stringify(object) + " was saved successfully.");
},
error: function(model, error) {
console.log("There was an error! The following model and error object were provided by the Server");
console.log(model);
console.log(error);
}
});
What about authentication and security?
Parse has a User based authentication system, which pretty much allows you to store a base of users that can manipulate the data. If map the data with User information, you can ensure that only a given user can manipulate specific data. Plus, in the settings of your Parse application, you can specify that no clients are allowed to create classes, to ensure innecesary calls are performed.
Did you REALLY used in a web application?
Yes, it was my tool of choice for a medium fidelity prototype.
Firebase.com
Firebase's main feature is the ability to provide Real Time to your application without all the hassle. You don't need a MeteorJS server in order to bring Push Notifications to your software. If you know Javascript, you are half way through to bring Real Time magic to your users.
How does a Firebase looks in Javascript?
Firebase works in a REST fashion, and I think they do an amazing job structuring the Glory of REST. As a good example, look at the following Resource structure in Firebase:
https://SampleChat.firebaseIO-demo.com/users/fred/name/first
You don't need to be a rocket scientist to know that you are retrieve the first name of the user "Fred", giving there's at least one -usually there should be a UUID instead of a name, but hey, it's an example, give me a break-.
In order to start using Firebase, as with Parse, add up their CDN Javascript
<script type='text/javascript' src='https://cdn.firebase.com/v0/firebase.js'></script>
Now, create a reference object that will allow you to consume the Firebase API
var myRootRef = new Firebase('https://myprojectname.firebaseIO-demo.com/');
From there, you can create a bunch of neat applications.
var USERS_LOCATION = 'https://SampleChat.firebaseIO-demo.com/users';
var userId = "Fred"; // Username
var usersRef = new Firebase(USERS_LOCATION);
usersRef.child(userId).once('value', function(snapshot) {
var exists = (snapshot.val() !== null);
if (exists) {
console.log("Username "+userId+" is part of our database");
} else {
console.log("We have no register of the username "+userId);
}
});
What about authentication and security?
You are in luck! Firebase released their Security API about two weeks ago! I have yet to explore it, but I'm sure it fills most of the gaps that allowed random people to use your reference to their own purpose.
Did you REALLY used in a web application?
Eeehm... ok, no. I used it in a Chrome Extension! It's still in process but it's going to be a Real Time chat inside a Chrome Extension. Ain't that cool? Fine. I find it cool. Anyway, you can browse more awesome examples for Firebase in their examples page.
What's the magic of these services? If you read your Dependency Injection and Mock Object Testing, at some point you can completely replace all of those services for your own through a REST Web Service provider.
Since these services were created to be used inside any application, they are CORS ready. As stated before, I have successfully used both of them from multiple domains without any issue (I'm even trying to use Firebase in a Chrome Extension, and I'm sure I will succeed soon).
Both Parse and Firebase have Data Browser managers, which means that you can see the data you are manipulating through a simple web browser. As a final disclaimer, I have no relationship with any of those services other than the face that James Taplin (Firebase Co-founder) was amazing enough to lend me some Beta access to Firebase.
You actually CAN use SQS from the browser, even without CORS, as long as you only need the browser to send messages, not receive them. Warning: this is a kludge that would make my CS professors cry.
When you perform a GET request via javascript, the browser will always perform the request, however, you'll only get access to the response if it was from the same origin (protocol, host, port). This is your ticket to ride, since messages can be posted to an SQS queue with just a GET, and who really cares about the response anyways?
Assuming you're using jquery, your queue is https://sqs.us-east-1.amazonaws.com/71717171/myqueue, and allows anyone to post a message, the following will post a message with the body "HITHERE" to the queue:
$.ajax({
url: 'https://sqs.us-east-1.amazonaws.com/71717171/myqueue' +
'?Action=SendMessage' +
'&Version=2012-11-05' +
'&MessageBody=HITHERE'
})
The'll be an error in the console saying that the request failed, but the message will show up in the queue anyways.
Have you considered JSONP? That is one way of calling cross-domain scripts from javascript without running into the same origin policy. You're going to have to set up some script somewhere to send you the data, though. Javascript just isn't up to the task.
Depending in what kind of data you want to send, and what you're going to do with it, one way of solving it would be to post the data to a Google Spreadsheet using Ajax. It's a bit tricky to accomplish though.Here is another stackoverflow question about it.
If presentation isn't that important you can just have an embedded Google Spreadsheet Form.
What about mailto:youremail#goeshere.com ? ihihi
Meantime, you can turn on some free hostings like Altervista or Heroku or somenthing else like them .. so you can connect to their server , if i remember these free services allows servers p2p, so you can create a sort of personal web services and push ajax requests as well, obviously their servers are slow for free accounts, but i think it's enought if you do not have so much users traffic, else you should turn on some better VPS or Hosting or Cloud solution.
Maybe CouchDB can provide what you're after. IrisCouch provides free CouchDB instances. Lock it down so that users can't view documents and have a sensible validation function and you've got yourself an easy RESTful place to stick your data in.

Categories

Resources