I'm not certain it's even possible, but is there a way to keep user information secure across multiple pages while only using javascript?
I have a predefined set of details recovered from three separate API requests, initial call sends user credentials to the login_api via a POST and returns a small set of data (OAuth2 token, user birth name, etc.), the ensuing calls fire, upon success, for 2 lanes of products via GET calls, these requests return a list of products for each lane which is perceived as what this user is licensed to view.
I've not had a great deal of experience in setting up secure user authentication and remembered data across a multi-paged website so I want to ensure I am taking the proper approach.
With the functions below I can create _private variables inside of functions that utilize that data.
All remembered data is applied within the XHR responses to the cookie storage area, it never leaves the scope of the request function.
From that point forward all data is retrieved via cookies, used within a singular function scope, never leaving the scope of the function it is utilized in. Each time the data is required it is re-fetched from the cookies. I'm not certain how secure cookies are, I debated clearing cookies each time the data is recovered and re-applying updated values upon the function's completion, but thought it overkill.
If any piece of relevant cookie data is not present on page load they're redirected to the login page and all relevant cookie data, if present, is removed.
Is there any way to improve retaining an OAuth2 token and handful of user details across multiple pages without leaking user information with only javascript?
NOTE
This is within a rather old internal website and in keeping things familiar for the team we're using ES5 and below, it's moving away from internal use only.
var config = Object.create(null);
config.expire_item = 30; // minutes
function dataref() {
// setup objects to store details in
var output;
output = Object.create(null);
output.access = Object.create(null);
output.licensed = Object.create(null);
output.token = "_token";
// apply predefined names as object values
// cookies in this namespace holds user name
output.fname = "_fname";
// cookies in this namespace store true/false flags
output.has_access.ces = "ces_license";
output.has_access.ezg = "ezg_license";
// cookies in this namespace hold pipe & comma delimited product lists
output.licensed_for.ces = 'ces_products';
output.licensed_for.ezg = 'ezg_products';
// ...etc.
return function () {
// return object with predefined names for cookies
return output;
}();
}
function apply_userdata(fn) {
// get predefined cookie names
var _data = dataref();
return function () {
// apply function to all namespaces
fn(_data.token);
fn(_data.fname);
fn(_data.access.ces);
fn(_data.access.ezg);
fn(_data.licensed.ces);
fn(_data.licensed.ezg);
}();
}
function resetCookieExpire(name) {
// updates cookie expiration period.
return setCookie(name, getCookie(name), option.expire_item);
}
function getUserSensativeData(name) {
// retrieve cookie value
return getCookie(name)
}
function deleteUserSensativeData(name) {
// remove cookie name/value
return deleteCookie(name);
}
I should preface this with "I'm no auth expert either", however I have worked with several different kinds of user auth in the past on multiple projects. There's a little bit of missing information that seems implied by what you're saying, but it appears you are either using oauth2 implicit flow or oauth2 authorization code flow. in either circumstance, in order to persist across separate page loads, you would have to use either cookies or local storage as you currently are, unless it's a single page application, in which case it sounds like it's not.
Based on how you've described this project it sounds like you're trying to sunset it, that being said, if you really feel bad about storing these client side credentials you could switch to an OIDC style flow that uses secure=true;httpOnly=true cookies that automatically get sent with each request. That sounds like it's not an option for you.
Oauth2 is considered secure, and storing a client side credential for repeated use is not "breaking" any rules. The reason storing a client side credential can be considered vulnerable is because of XSS or CSRF attacks
Having a Content Security Policy goes a long way too.
There are additional precautions you can take, such as having a short expire time (1 hour is pretty common) or even having the ability to manually expire access_tokens in an emergency. Hope this helps.
Related
Not sure if the title summarises my question well.
Basically, I am trying to authenticate routes such as checking if user exists etc. I only want to allow
requests coming from my frontend application to be approved, but, since no user is signed in there is no token to send.
Api request -
mywebiste/checkUser/email
This route is unprotected on my backend because no user is logged in.
BUT I want to protect this route, in such a way that it's accessible only from the frontend.
Some ideas I came up with were adding specific headers tag from the frontend and check them on the backend, but that could be easily replicated, is there something more secure like using tokens etc.
I am using React and Node.js
Same origin policy is going to give you some basic protection, but basically if an API endpoint is exposed publicly, it's exposed publicly. If you don't want that route to be publicly accessible you need to add access control.
If you use that route to check if a user is already registered, you could, for example, merge it with the user registration route and send a different error code if the user already exists (which is not a great idea because it leaks which emails are registered on your system).
You can verify that a request was originated by a user (by authenticating him) but you cannot verify that a request comes from a particular client because of these two reasons :
If you include some API key in your client (web page or other), it's easily retrievable by everyone (the best thing you could do is offuscate it which makes things slightly harder but still possible)
If you send an API key over the network it's easily retrievable as well
The only thing you could do is prevent other web pages from calling your backend on behalf of the user, by using CORS (which is actually active by default if you dont specify an Access-Control-Allow-Origin header)
I ended up creating a kind of working solution, so basically, I create a new base64 string on my frontend and attach that to the header while making a request to the backend. The base64 string is different every minute, so even if the header is copied, it differs every minute and is combined with your secret key.
I have made a package so that people can use it if they want - https://github.com/dhiraj1site/ncrypter
You can use it like so
var ncrypter = require('ncrypter');
//use encode on your frontend with number of seconds and secret key
var encodedString = ncrypter.encrypt(2, 'mysecret1')
//use decode on your backend with same seconds and secret
var decodedString = ncrypter.decrypt(encodedString, 2, 'mysecret1');
console.log('permission granted -->', decodedString);
I just want everyone to know that I am in no way a professional web developer nor a security expert. Well, I'm not a beginner either. You can say that I am an amateur individual finding interest in web development.
And so, I'm developing a simple, small, and rather, a personal web app (though I'm thinking of sharing it to some friends and any individual who might find it interesting) that audits/logs every expense you take so you can keep track of the money you spend down to the last bit. Although my app is as simple as that (for now).
Since I'm taking my app to be shared to some friends and individuals as a factor, I already implemented a login to my application. Although it only needs the user key, which acts as the username and password at the same time.
I've used jQuery AJAX/PHP for the login authentication, as simple as getting the text entered by such user in the textbox, passing it to jQuery then passing it to the PHP on the server to verify if such user exists. And if yes, the user will be redirected to the main interface where his/her weekly expense will be logged.
Much for that, my main problem and interest is within the security, I've formulated a simple and a rather weak security logic where a user can't get to the main interface without having to login successfully first. The flow is like this.
when a user tries to go the main interface (dashboard.php) without successfully logging in on the login page (index.php), he will then be prompted something like "you are not able to view this page as you are not logged in." and then s/he will be redirected back to the login page (index.php)
How I've done this is rather simple:
Once a user key has been verified and the user is logged in successfully, cookies will then be created (and here is where my dilemma begins). the app will create 2 cookies, 1 is 'user_key' where the user key will be stored; and 2 is 'access_auth' where the main interface access is defined, true if logged in successfully and false if wrong or invalid user key.
Of course I'm trying to make things a little secure, I've encrypted both the cookie name and value with an openssl_encrypt function with 'AES-128-CBC' with PHP here, each and every user key has it's own unique iv_key to be used with the encryption/decryption of the cookie and it's values. I've encrypted the cookie so it wouldn't be naked and easily altered, since they won't know which is which. Of course, the encrypted text will vary for every user key since they have unique iv_keys although they have same 'key' values hard-coded in the PHP file.
pretty crazy right ?. yea i know, just let me be for that. and as how the main interface (dashboard.php) knows if a user has been logged in or not and to redirect them back to the login page (index.php) is purely easy. 'that' iv_key is stored together with the user_key row in the database.
I've attached a JavaScript in the main interface (dashboard.php) which will check if the cookie is equal to 2, if it is less than or greater than that, all those cookies will be deleted and then the user will redirected to the login page (index.php).
var x = [];
var y = 0;
//Count Cookie
$.each($.cookie(), function(z){
x[y] = z;
y++;
});
//Check if Cookie is complete
if (x.length != 2) {
//If incomplete Cookie - delete remaining cookie, prompt access denied, and redirect to login page
for (var i = 0; i < x.length; i++) {
$.removeCookie(x[i], { path: '/' });
};
alert("You are not allowed to enter this page as you are not yet logged in !.");
window.location.href = "index.php";
} else {
//If complete Cookie - authenticate cookie if existing in database
}
As you can see, the code is rather incomplete, what I want to do next after verifying that the count of the cookies stored is 2 is to dig in that cookie, decrypt it and ensure that the values are correct using the 'iv_key', the iv_key will then be used to decrypt a cookie that contains the user_key and check if it is existing in the database, at the same time the cookie that contains access_auth will also be decrypted and alter it's value depending on the user_key cookie's verification (returns true if user_key is found in database, otherwise false). Then after checking everything is legitimate, the cookies will then be re-encrypted using the same iv_key stored somewhere I don't know yet.
My question is and was, 'where is a safe location to store the encryption/decryption key?' and that is the 'iv_key'. I've read some threads and things about Session Variables, Local Storage, and Cookie. And I've put this things into consideration.
SESSION - I can use session storage of PHP to store the key in something like $_SESSION['user_key'] then access it later when needed be. But I've read an opinion saying that it is not recommended to store sensitive information including keys, passwords, or anything in session variable since they are stored somewhere on the server's public directory. And another thing is the session variable's lifespan, it lasts for around 30 minutes or so. I need to keep the key for as long as the user is logged in. The nice thing I find here is that, it'll be a little bit hard to alter the value and I don't need to encrypt it (the iv_key) here since it is server sided, and hidden to the naked eye, well not unless when being hacked of course. What I mean is, they don't appear on the debugging tools just like how localStorage and Cookies are visible there.
LOCAL STORAGE - this eliminates my problem of lifespan, since it will be stored in the localStorage vault of the browser not until I close the browser. But the problem here is that the values can easily be changed via console box of the debugger tool, I can eliminate this problem by encrypting the 'iv_key', but what's the point of encrypting the encryption/decryption key? Should I encrypt it using itself as the 'iv_key' too? Or I can use base64_encode?, which eliminates the security of needing a key, and can be decrypted so easily with no hassle.
COOKIE - this one adopts two problems, one from session variable and one from localstorage. From session variable, I mean is the lifespan. As far as I've read, cookies last for about 1 hour or so, but still depends if an expiry has been declared when setting the cookie. The other is from localStorage, since it can easily be altered via console box of the debugger tools too. Although I've already encrypted 2 Cookies beforehand, but what's the point of storing the encryption key together with the values you encrypted?, should I go on with this and encrypt the 'iv_key' by itself, just like what I might do with localStorage?.
I'm lost as to where I should save this sensitive 'encryption_key' as it is crucial in encrypting and decrypting the cookies and other information my app needs.
Why am I so devastated with such security, despite having a simple worthless app?.
Well, because I know and I believe that I can use this as a two-step further knowledge which I can used with my future projects. I maybe doing web development for fun right now. But I'm taking it to consideration as my profession. And so, I want my apps to be secure in any means.
All meteor methods can be called same way from client and server side.
Let's say user knows or can predict all the method names on server, then he is able to call them and use it's result however he want.
example:
A method which performs cross domain http request and return response can be used to overload server by calling huge amounts of data Meteor.call(httpLoad, "google.com");, or a method which load data from mongo can be used to access database documents if the client know document _id Meteor.call(getUserData, "_jh9d3nd9sn3js");.
So, how to avoid this situations, may be there is a better way to store server-only functions than in Meteor.methods({...})?
Meteor methods are designed to be accessed from the client, if you don't want this, you just need to define a normal javascript function on the server. A really basic example would be:
server/server.js:
someFunction = function(params) {
console.log('hello');
}
As long as it's in the server folder, the function won't be accessible from the client.
For coffeescript users, each file is technically a separate scope, so you would have to define a global variable with #, e.g.
#someFunction = (params) ->
console.log 'hello'
or if you want to scope the function to a package:
share.someFunction = (params) ->
console.log 'hello'
If you have methods that need to be accessible from the client but only for say admin users, you need to add those checks at the start of the meteor method definition:
Meteor.methods({
'someMethod': function(params) {
var user = Meteor.user();
if (user && (user.isAdmin === true)) {
// Do something
} else {
throw new Meteor.Error(403, 'Forbidden');
}
}
});
I'm not going to vouch for the security of this example - it's just that, an example - but hopefully it gives you some idea of how you would secure your methods.
EDIT: Noticed the other answers mention using a if (Meteor.isServer) { ... } conditional. Note that if you are doing this inside methods which are also accessible on the client, the user will be still be able to see your server code, even if they can't run it. This may or may not be a security problem for you - basically be careful if you're hardcoding any 3rd-party API credentials or any kind of sensitive data in methods whose code can be accessed from the client. If you don't need the method on the client, it would be better to just use normal JS functions. If you're wrapping the whole Meteor.methods call with a isServer conditional, the code will be on the server only, but can still be called from the client.
as rightly stated in other answers, your methods will always be accessible from the client (per design). yet, there is a simple workaround to check if the call originates from the client or from the server. if you do a
if ( this.connection == null )
this will return true if the method was called from server. like that you can restrict the method body execution to 'secure' calls.
I think this page explains it: http://meteortips.com/first-meteor-tutorial/methods/
I'm quoting:
"The safer approach is to move these functions to the isServer conditional, which means:
Database code will execute within the trusted environment of the server.
Users won’t be able to use these functions from inside the Console, since users don’t have direct access to the server.
Inside the isServer conditional, write the following:
Meteor.methods({
// methods go here
});
This is the block of code we’ll use to create our methods."
and so on. I hope this helps.
With proper app design, you shouldn't care whether a request was through the web UI or via something typed in a console window.
Basically, don't put generic, abuse worthy functions in Meteor.methods, implement reasonable access controls, and rate-limit and/or log anything that could be a problem.
Any server-side function defined in Meteor.methods will have access to the current user id through this.userid. This userid is supplied by Meteor, not a client API parameter.
Since that Meteor Method server-side code knows the login status and userid, it can then do all the checking and rate limiting you want before deciding to do that thing that the user asked it to do.
How do you rate limit? I've not looked for a module for this lately. In basic Meteor you would add a Mongo collection for user actions accessible server-side only. Insert timestamped, userid specific data on every request that arrives via a Meteor method. Before fulfilling a request in the server method code, do a Mongo find for how many such actions occurred from this userid in a relevant period. This is a little work and will generates some overhead, but the alternative of rate-limiting via a server-wide underscore-style debounce leaves a function open for both abuse and denial-of-service by an attacker.
i am getting remote JSON value into to my client app as below.
var $Xhr = Ti.Network.createHTTPClient({
onerror : function($e) {
Ti.API.info($e);
},
timeout : 5000,
});
$Xhr.open("GET", "http://***********.json");
$Xhr.send();
$Xhr.onload = function() {
if ($Xhr.status == 200) {
try {
Ti.API.info(this.responseText);
} catch($e) {
Ti.API.info($e);
} finally {
$Xhr = null;
}
}
};
My json URL is static. i would like to protect this URL from stranger eyes after creating APK file or publishing for iOS.
Also my server side support PHP. I have thouhgt MD5, SHA etc. but i didn't develop any project about this algortim.
Do you have any suggestion or approach?
Thank you in advance.
I would just say that it is not possible for you to "hide" the end point. Your url will always to visible to the user because otherwise user's browser wouldn't know how to actually post it to your server.
If you meant to only hide the json object, even that is not totally possible. If your javascript knows what the values are then any of your client smart enough to understand javascript will be able to decode your encoded json object. Remember, your javascript has decoded object and a user would have full access to it. There is no protection against that. At best, you can hide it from everyday user by encoding to with md5 or sha as you put it.
I you wish to restrict access to app user only, you will need to authenticate your users first.
Once they are authenticated, you should generate a hash by concatenating userid (or any user identifying data) and a key that you know (a string will do it), and hashing it using any hashing method, md5 would be enough for that kind of usage I guess, SHA is good anyway.
The next step would be to send this hash with every AJAX request to your server. consider it as an additional data.
Finally, server-side, before treating the request and fetching the data to be sent, just generate a hash the same way you did in your app, using the userid of the requesting user and the same "secret" key you chose. You can now compare both hashes and see if they're identical. If not, then it's probably that someone tried to forge a request from outside your app.
Note that it could be possible for someone authenticated to get his hash (which depends on his ID) and then use it in one of his applications, so it may be a good idea to track the requests server-side in order to check if there's any suspicious usage of your API. You could aswell change your "secret key" regularily (forcing an update of your app though) or define an array with a different key for each day of the year in both your app and server code, so that each individual hashkey will change everyday, recurring each year.
I am validating my users with header variables that I display in my .net application and my question is how can I validate that the user that is on the on the current page is allowed to proceed to any other pages.
I want to check the name from an array or names and if they are not listen then it will redirect them to an error page letting them know they do not have access.
I was going to take the path of sql authentication but that would just require an additional login page and since I already check the header variables I thought I could just go about this way. Any help regarding this would be great!
You should never trust ANY data sent from the client to your server. The header-variables can easily be modified to represent anything. One could easily forge the header to spoof themself for being somebody else (like admin in worst case).
You should really consider some sort of authentication that requires a combination of username + password, I'm afraid.
If you REALLY want to rely on the headers though, add a header that identifies themself, like X-USERNAME:CSharpDev4Evr, and then just parse that one and match against the array on back-end.
I don't know any C#.NET, but here's a JavaScript-snippet showing the principle:
var headerUsername = "CSharpDev4Evr";
var validUsernames = ["Eric", "CSharpDev4Evr", "Stackoverflow", "root"];
// Check if we are in the array
// Re-direct if we're not
if (validUsernames.indexOf(headerUsername) === -1)
window.location = 'error.html';
// Proceed with other authenticated stuff here
// ...