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.
Related
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.
I am using Thinktecture AuthorizationServer (AS) and it is working great.
I would like to write a native javascript single page app which can call a WebAPI directly, however implicit flow does not provide a refresh token.
If an AJAX call is made, if the token has expired the API will send a redirect to the login page, since the data is using dynamic popups it will this will interrupt the user.
How does Facebook or Stackoverflow do this and still allow the javascript running on the page to call the APIs?
Proposed Solution
Does the below scenario sound sensible (assuming this can be done with iframes):
My SPA directs me to the AS and I obtain a token by Implicit Flow. Within AS I click allow Read data scope, and click Remember decision, then Allow button.
Since I have clicked Remember decision button, whenever I hit AS for a token, a new token is passed back automatically without me needing to sign in ( I can see FedAuth cookie which is remembering my decision and believe this is enabling this to just work).
With my SPA (untrusted app), I don't have a refresh-token only an access token. So instead I:
Ensure user has logged in and clicked remember decision (otherwise iframe wont work)
Call WebAPI, if 401 response try and get a new token by the below steps...
Have a hidden iframe on the page, which I will set the URL to get a new access-token from the Authorisation Server.
Get the new token from the iframe's hash-fragment, then store this in the SPA and use for all future WebAPI requests.
I guess I would still be in trouble if the FedAuth cookie is stolen.
Any standard or recommended way for the above scenario?
I understand that your problem is that the user will experience an interruption when the access token has expired, by a redirection to the login page of the authorization server. But I don't think you can and should get around this, at least, when using the implicit grant.
As I'm sure you already know, the implicit grant should be used by consumers that can NOT keep their credentials secret. Because of this, the access token that is issued by an authorization server should have a limited ttl. For instance google invalidates their access token in 3600 sec. Of course you can increase the ttl, but it should never become a long lived token.
Also something to note is that in my opinion the user interruption is very minimal, i.e if implemented correctly, the user will only have to authenticate once with the authorization server. After doing that (for example the first time when also authorizing the application access to whatever resources the user controls) a session will be established (either cookie- or token based) and when the access token of the consumer (web app using implicit grant) expires, the user will be notified that the token has expired and re authentication with the authorization server is required. But because a session already has been established, the user will be immediately redirected back to the web app.
If however this is not what you want, you should, in my opinion, consider using the authorization code grant, instead of doing complicated stuff with iframes.
In that case you need a server side web application because then you can keep your credentials secret and use refresh tokens.
Sounds like you need to queue requests in the event that an access token expires. This is more or less how Facebook and Google do it. A simple way using Angular would be to add a HTTP Interceptor and check for HTTP401 responses. If one is returned, you re-authenticate and queue any requests that come in after until the authentication request has completed (i.e. a promise). Once that's done, you can then process the outstanding queue with the newly returned access token from your authentication request using your refresh token.
Happy Coding.
Not sure if I understand your question but,
I would like to write a native javascript single page app which can call a WebAPI directly, however implicit flow does not provide a refresh token.
Summarize facts,
refresh token is sometimes used to be a part of A: Authorization Grant
https://www.rfc-editor.org/rfc/rfc6749#section-1.5
and as you said in implicit flow you dont get back refresh token, but only in Authorization Grant part
https://www.rfc-editor.org/rfc/rfc6749#section-4.2.2
so you can get back refresh token when issuing access token (refresh tokens are always optional)
https://www.rfc-editor.org/rfc/rfc6749#section-5.1
With my SPA (untrusted app), I don't have a refresh-token only an
access token. So instead I:
Ensure user has logged in and clicked remember decision (otherwise
iframe wont work)
Call WebAPI, if 401 response try and get a new
token by the below steps...
Have a hidden iframe on the page, which
I will set the URL to get a new access-token from the Authorisation
Server.
Get the new token from the iframe's hash-fragment, then
store this in the SPA and use for all future WebAPI requests.
SPA(you) have no idea if user selected remember decision. Its in AS direction and should be complete blackbox. Skip this step.
You can try to use access token and wait for result, always.
If access token has expired and you dont have refresh token, you still can create hidden iframe and and try to get new access token.
Lets assume your AS provide option to remember decision and wont change it in future, then: your iframe will get new access token without user interaction, then you will get result back in some unknown time limit.
Result can be checked by setInterval for read specific cookie or iframe postmessage.
If you dont get back data in time limit, then one from following scenarios occured:
lag, AS is slow, connection is slow or time limit is too tight
user didnt select remember decision
In this case:
show iframe with login
I consider scenario above as good practise if AS doesnt provide refresh tokens, but I also guess every AS like that wont provide remember option as well.
StackOverflow <---> Google scenario (I can only guess)
User login, authorization request occured
User logs in, SO gets access token
SO tries to use access token
SO gets back result + refresh token
SO saves refresh token
SO has permanent access to users Google account
In Google o-Auth , the access token will only be valid for 1 hour, so you need to programmatically update your access token in each one hour, simple you can create web api to do so,you need to have a refresh token, and also that refresh token will not be expired , using c# code, I have done this.
if (dateTimeDiff > 55)
{
var request = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/oauth2/v3/token");
var postData = "refresh_token=your refresh token";
postData += "&client_id=your client id";
postData += "&client_secret=your client secrent";
postData += "&grant_type=refresh_token";
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
request.UseDefaultCredentials = true;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse)request.GetResponse();
string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
}
you need to save the last updated date time of the access token somewhere(say in database), so that , whenever you have to make a request , so you can subtract that with current date time , if it is more than 60 minutes , you need to call the webapi to get new token .
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.
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.
Is there a way to validate the response from say:
FB.api(
{
method: 'fql.query',
query: 'SELECT name, pic FROM profile WHERE id= ' + FB.getSession().uid
},
function(response) {
//...
}
);
Validating the cookie for login is easy enough using a MD5 hash and the application secret key compared to the provided sig parameter. However in the case of the api calls, what would stop someone from using firebug to change the response? Obviously this can be done on the back end for sensitive information but i'd like to keep as much of the back and forth bandwidth to Facebook on the clients end as possible.
Any thoughts?
I can't think of anything harmful the user can do other than breaking his own experience in your application UNLESS you are getting these inputs (responses) and processing them/saving them to the DB for example:
Having an input field where the user can update his FB status through it, and you want to save that to your own DB too?
In this case you would/SHOULD do the usual input validations (mysql_real_escape ..etc) anyway.
Saving the user Email?
You already can get almost all the information about the user using server-side calls once the user is authenticated and grant your application access..for instance to save the user email you shouldn't wait for the user to send it to you when you can acquire it using the email permission
Any validation you might do in JavaScript(1) would be something the user could overcome with a little JS of their own.
If you need to ensure that communications to/from Facebook are secure and not interfered with... then do it on the server.
(1) e.g.
if you had a validateFacebookResponse(resp); function... an end user simply needs to re-declare the function...
function validateFacebookResponse(resp){
return true;//always return true!
}
and any "security" you had is out the window.