server request security with tokens - javascript

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.

Related

Is it safe to expose Stripe charge id and account Id of connected account to client side?

I have an ajax call I am doing to my backend and I was wondering if it's safe to expose the charge id and the connected account id to the client side?
I don't have any secret keys or anything on the browser side.
Thanks!
i call this once the refund button is clicked on:
$.ajax({
type: "POST",
data: {amount: pennies.toFixed(0), charge: chargeId, account: accountId},
url: "/refund",
success: function(data){
//f.e. set to modal
$('#refund_dialog').modal('hide')
$('#refund_dialog').on('hidden.bs.modal', function () {
alert(JSON.stringify(data));
})
},
error: function(err) {
$('#refund_dialog').modal('hide')
$('#refund_dialog').on('hidden.bs.modal', function () {
alert(err.responseText);
})
});
It's safe, these IDs are not useful without API keys.
It's safe, but why you need to do so?
It is NOT safe.
What would happen if a hacker decided to create a program that makes millions of requests for refunds by entering in random account IDs, charge ID and refund IDs?
The result could be that thousands of refunds are requested...
Instead you should store all of this data (account ID, charge ID and refund ID) into a table in a database on the server that is handling the transaction (or forwarding it).
The three pieces of data should be stored using a key that is generated using some a UUID generator such as OpenSSL to ensure no conflicting IDs are generated.
The UUIUD should be the key for the data in the database.
The refund button should simply send that same UUID via AJAX, at which point the server will look up the necessary data with the UUID and then send the relevent data via Stripe.
Another reason why its NOT safe
By returning the account ID back to the user, if they have a web browser which has been compromised by malicious extensions / add-ons / plugins / etc, then now a hacker could get ahold of the user's account ID giving them a crucial piece of information that they could use to forge other requests etc.
Never assume that data sent to the client will be reliably received or returned.
Data should only be sent to the client if that data is to be displayed to the client (such as a page which has their account ID on it).
At the same time, the data sent to the client should NEVER be used as input for any server-side operations as this allows for requests to be forged, potentially letting a hacker access your back-end systems.
Another way its not safe
If a hacker is familiar with your back-end system (Stripe or whatever), then they can determine your API secret key if they are able to perform a Man In the Middle type of attack on your server by forwarding network requests to and from remote locations. This could allow for a different part of your site completely unconnected to any Stripe interactions to be a gateway that could allow them to send specially crafted requests (with random account ID, charge ID, amount) , and then see the data after it is encrypted with your API Key, and be able to decode that data in order to get your secret API key.
Instead, by using a UUID, a hacker has no way of connecting the two pieces of the puzzle together, thus making it safe from M.I.T.M. attacks.

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 }

Persisting a security token between calls

We are creating a prototype application as follows:
We have a html web site using knockoutjs
Using qQuery/Ajax it communicates with Web Api services
We only want the services to be accessed by authorised users. So we have written in security that can validate the user based on username/password
So next I guess we need to pass back some type of token to the client which it uses in further communications with the API services.
What I would like to know is how this is stored on the client so it can be passed back to the server again for the next call?
I assume the client makes an initial call passing in the user name and password over HTTPS and gets back a token. You question is to how to store the token? I assume your application is an SPA. If so, why not just store it in a JavaScript variable? If you do not use a cookie, you avoid XSRF. Of course, you must ensure the user name and password are never stored in the client side and that the life time token of your token is finite and preferably as small as possible.
EDIT:
If you can regenerate the token with every page (since it is not SPA), it is even better and you make the life time of token very small. You can use code like this. I use Authorization header and bearer scheme but you can use your own scheme as well, if no standardization is needed.
var accessToken = ''; // Write out the token into this variable in the server side (view)
$.ajax({
type: 'GET',
url: 'http://whatever',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
headers: { 'Authorization=': ='Bearer ' + accessToken },
success: function (data) {
}
});
So we have written in security that can validate the user based on username/password
This sentence basically means that you need to store the username and password in your javascript file in order to be able to call the service, unless of course you want to ask the user to enter his credentials on every single action he performs. I hope this is not something you are wiling to do at the moment. If it is then you can stop reading my answer and store the username and password in your javascript file.
At this stage it is more than clear that your security should be handled differently. Your Web API should not be protected by a username and password but by a token. Here's how this could work in practice. You will have an action that will take the username and password, validate them and if successful it will return a token. This token could contain the encrypted username. So your javascript will ask the user for his username and password, call the Login method and it could store the token. Then it will use this token on subsequent calls. The API will in turn decrypt it in order to extract the username.
What I would like to know is how this is stored on the client so it can be passed back to the server again for the next call?
Cookies. You will send token as a cookie, and it will be sent automatically when user requests your page.
create a server side session, for the once authorised md5(username) md5(password).
generate an uuid per request, and return it in the response.
basic model is called token exchange and it is reliable (no m.i.t.m) even w/o SSL.

Security in a Javascript based app -refreshing a users hash

I'm developing an hybrid mobile app using HTML/CSS/JS, I'm going over security with login information, the system I have set up creates an hash after a user logs in, this hash has a time limit and is set via localStorage
Essentially, I would have something like this is localstorage:
hash
5f4a09cfec2a6d8f306eecb3844e33e9
hash_expiration
1373012945
password
*encryted user password*
This hash is sent to my server for validation in the header of all my AJAX requests (accompanied by the user id for database matching)
I'm mostly opening this topic to discuss best practices on how to deal with recreating hash keys, I need to figure out a way to refresh a users hash key.
Considering my experience with AJAX and JS is still rather limited, I thought about using the AJAX setup to check for a new hash, like so:
$.ajaxSetup({
beforeSend: function(xhr, settings) {
var time = new Date().getTime(); //unix time
var hash_time = localStorage.getItem("hash_expiration");
if(time>hash_time){
//ajax request to fetch new hash, async: false to make sure this completes before continuing with other AJAX calls
}
}
});
I would send the user id and his encrypted password to verify him and return a new hash.
Should I be sending AJAX requests in the ajaxSetup's beforeSend? How would this conflict with other beforeSends across my application?
Basicallly on the clients side you shouldnt have anything except hash. On the server side this hash must be associated with user it belongs to, expire time and anything else you need.
Send this hash with each request, and on server side validate it. When it expires you have to send (server) appropriate headers like 401 - Unauthorized. Client have to understand that response and try to exchange hash to new one. And finally when client gets new valid hash it can resume sending requests.
... and you shouldnt check expire time at client, this job for server.
thanks.

Categories

Resources