Securing REST API calls with client-side token - javascript

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 }

Related

How long to crack HMAC sha256 digest private key given data

We've built a javascript module which can be embedded in third-party webpages. When this client module is initialized, it executes a transaction within our web application via a cross-site request.
The transaction consists of an external uuid, an email, and some additional meta properties. This message is signed with an HMAC sha256 digest, using our partner's private API key.
Ruby example:
data = {
uuid: "ABCAFAFDS",
email: "email#gmail.com",
meta: {}
}
private_key = "Qd9fe0y2ezqfae4Qj6At"
signature = OpenSSL::HMAC.hexdigest(
OpenSSL::Digest.new("sha256"),
private_key,
data.to_json
)
Within the third-party webpage, the javascript client is then initialized with the signature and the data:
new Client(signature, data).execute();
Initially, our plan was to allow the client to create a partial / incomplete transaction within our system and then require a subsequent back-end request via our REST API to confirm / finalize the transaction. Assuming that we can secure the front-end, however, it would be preferential to remove the back-end confirmation requirement.
Can we reasonably secure the client code using signed messages in this fashion? If the data and the signed message is available in the client, how difficult would it be for a bad actor to brute force the API private key length, given the length above?
most internet traffic has signed tokens on the client these days. All your gmail logins, facebook logins, etc do this so it is fairly standard. I'd recommend using an existing standard (and 3rd party library) rather than roll your own token though. This will let you leverage other people's expertise in this area.
JWT (json web token) is in common use and there are many libraries for working with JWT's. See https://jwt.io for more information.

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.

Protect PHP endpoints called by AJAX

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);
}

server request security with tokens

I have built a browser game and now I'm working on making it a bit more secure. Since all server requests are initiated from javascript even kids could tamper data on the server. I've been reading through questions on stackoverflow and implemented sending/receiving a token in my requests however I am regenerating this token on every request to the server and send the new one back to the client for the next call. Requests are made through https and are of type POST.
Here's the token flow on client side:
var token = 'abcd1234';
$.ajax({
url: "index.php",
type: "post",
data: {
method: "score",
value: 50
}
});
$(document).ajaxSend(function(e, xhr, o){
o.data += '&token=' + token;
});
$(document).ajaxComplete(function(e, xhr, o){
var data = JSON.parse(xhr.responseText);
token = data.token;
});
And on server side:
if (!isset($_POST['token']) || ($_POST['token'] != $_SESSION['token']))
{
die();
}
else
{
// generate new token and send it back along with the response
}
So my question would be if this token increases the security of my server requests or not and what can be done to further increase the security?
EDIT This is a facebook game, all code is javascript and the server side simply handles updating the database.
I dont really think tokens do alot when using Ajax.
You should just validate all your forms and data server sided with the users session because the login itself is the most realiable way to identify a user.
A token an merely help to make session stealing/riding harder but if you code your session handle to logout the user on changed IP adress this should be fair secure enough.
I have an online game aswell and I dont do more but validate all forms and values against injection, valid data and check the login/session every time correctly and never had any bad experience with that.
One more thing I do is security issue is that you should flag your admin accounts with a special attribute that it requires a special IP range to login, then I fetch the ip range with a whois lookup on ripe.net and enter it into the database and look if the users actual IP is inside the min and max ip, this way maybe 1 of 1000 attackers would have the correct IP adress to login with the admin account even if they achive the login data.
Remember that the generated token will be received and send with every normal ajax request and someone who want to harm you and your page will analyse your form and request data and then simply copy that process.
It will make it harder for script kiddies, but not for professional intruders.
Its all just a matter about how paranoid you are about security issues and how skilled your possible attackers are.
As Steini already stated the ONLY reliable login system is done with session. The client side solution has got infinity security issues.
You can for example make the system using session and than use Javascript to ask php if the user is logged, and which privilege it has.
This said you can use PDO to increment the security, you can also fetch all the data from all the form and all variables that are passed through browser alone to exclude some issues.
Without a secure login system your game will be a security bomb and will create you trouble soon or later.

Authentication for a SPA and a node.js server

I have a very simple node.js app built on express which has been handling authentication using a session memory store. Basically a user logs in by:
app.post('/sessions', function(req, res) {
// check username/password and if valid set authenticated to true
if (authenticated){
req.session.user = req.body.username;
} ...
});
Then in each call from the browser a requiresLogin middleware function is called which checks to see if that user property on the session has been set.
I'm now transitioning the app to basically just provide a service that may or may not be consumed in the browser, so instead of using cookies/sessions, I'm considering changing the system so that one would post to /getToken (instead of /sessions) which would return a temporary random token associated with a user's account that could then be used for a period of time to access the service. Using the service would then require a valid token to be included in each call. (I assume this would be better than passing the username/password each time so that the password would not have to be stored in memory on the client's computer after the call to get token?)
Would such a system basically be just as secure as the above current system or Is there a much more standard/safe way to handle this? What's the standard way to handle something like this?
Thanks in advance for you help!
What you are looking for is called an HMAC and there is a great article here to get ideas on how to implement for your service.
As to whether session based security is more secure than public/private keypairs is widely debated and really depends on the implementation/application. In your case, since you want per request authentication on a public facing API, the HMAC is the way to go.

Categories

Resources