I am starting to build/design a new single page web application and really wanted to primarily use client-side technology (HTML, CSS, JavaScript/CoffeScript) for the front-end while having a thin REST API back-end to serve data to the front-end. An issue that has come up is about the security of JavaScript. For example, there are going to be certain links and UI elements that will only be displayed depending on the roles and resources the user has attached to them. When the user logs in, it will make a REST call that will validate the credentials and then return back a json object that has all the permissions for that user which will be stored in a JavaScript object.
Lets take this piece of javascript:
// Generated by CoffeeScript 1.3.3
(function() {
var acl, permissions, root;
root = typeof exports !== "undefined" && exports !== null ? exports : this;
permissions = {
//data…
};
acl = {
hasPermission: function(resource, permission, instanceId) {
//code….
}
};
root.acl = acl;
}).call(this);
Now this code setup make sure even through the console, no one can modify the variable permissions. The issue here is that since this is a single page application, I might want to update the permissions without having to refresh the page (maybe they add a record that then needs to be added to thier permissions). The only way I can think of doing this is by adding something like
setPermission: function(resource, permission, instanceId){
//code…
}
to the acl object however if I do that, that mean someone in the browser console could also use that to add permissions to themself that they should not have. Is there any way to add code that can not be accessed from the browser console however can be accessed from code in the JavaScript files?
Now even if I could prevent the issue described above, I still have a bigger one. No matter what I am going to need to have the hasPermission functionality however when it is declared this way, I can in the browser console overwrite that method by just doing:
acl.hasPermission(resource, permission, instanceId){return true;}
and now I would be able to see everything. Is there anyway to define this method is such a way that a user can not override it (like marking it as final or something)?
Something to note is that every REST API call is also going to check the permissions too so even if they were to see something they should not, they would still not be able to do anything and the REST API would regret the request because of permissions issue. One suggestion has been made to generate the template on the server side however I really don't like that idea as it is creating a very strong coupling between the front-end and back-end technology stacks. If for example for whatever reason we need to move form PHP to Python or Ruby, if the templates are built on the client-side in JavaScript, I only have to re-build the REST API and all the front-end code can stay the same but that is not the case if I am generating templates on the server side.
Whatever you do: you have to check all the permissions on the server-side as well (in your REST backend, as you noted). No matter what hoops you jump through, someone will be able to make a REST call that they are not supposed to make.
This effectively makes your client-side security system an optimization: you try to display only allowed operations to the user and you try to avoid round-trips to the server to fetch what is allowed.
As such you don't really need to care if a user can "hack" it: if they break your application, they can keep both parts. Nothing wrong can happen, because the server won't let them execute an action that they are not authorized to.
However, I'd still write the client-side code in a way that it expect an "access denied" as a valid answer (and not necessary an exception). There are many reasons why that response might come: If the permissions of the logged-in user are changed while he has a browser open, then the security descriptions of the client no longer match the server and that situation should be handled gracefully (display "Sorry, this operation is not permitted" and reload the security descriptions, for example).
Don't ever trust Javascript code or the front-end in general. People can even modify the code before it reaches your browser (sniffers etc) and most variables are accessible and modifiable anyways... Trust me: you are never going to be safe on the front-end :)
Always check credentials on the server-side, never only on the front-end!
In modern browsers, you can use Object.freeze or Object.defineProperty to make sure the hasPermission method cannot be redefined.
I don't know yet how to overcome the problem with setPermission. Maybe it's best to just rely on the server-side security there, which as you said you have anyway.
Related
I'm new in Socket.IO, and I've just implemented the tutorial instruction about Socket.IO at http://socket.io/get-started/chat/. It's quite interesting.
But now I have a concern about security.
The client code for sending message is:
<script>
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg));
});
</script>
The function call socket.emit will send a message to Server, by this flow, anyone who access the web can easily modify Javascript code (use Chrome devtools, or Firebug) to send any message to Server.
For example, user can add the code lines as following:
<script>
$(document).load(function() {
socket.emit('chat message', '1122');
socket.emit('get_users', null);
socket.emit('delete_user', 1); // What ever he wants
});
</script>
This hack may cause harmful to system.
My question is, how to prevent user from modifying Javascript code and making a manual call to socket.io server, including users who have right to log in web application.
Any help would be great appreciated!
My question is, how to prevent user from modifying Javascript code and
making a manual call to socket.io server, including users who have
right to log in web application.
You cannot prevent user from modifying your Javascript code. It can be copied from the browser, modified and then run again. You cannot prevent that. You must safeguard things without relying on any code protection. Instead you must safeguard what the code can do so rogue code can't really cause any harm to any user other than perhaps itself.
The client can never be trusted. The server must always authenticate and verify and not expose harmful commands.
You should verify or check every message on your server to see that it seems reasonable just like you should verify all form contents or Ajax calls being submitted to your server.
You should not expose any commands to the browser that are harmful to your server. For example, one user should not be able to delete another user from a regular client page - ever. Basically a regular user should only be able to modify their own stuff.
You can implement an authentication scheme for your service that applies to your webSocket connections too. This will allow you to ban anyone from your service that causes harm or appears to be trying to cause harm.
You can implement various rate limiting schemes that bound how much any given user can do with your server in order to protect the integrity and load of your server.
You can prevent various types of automated operations by requiring a captcha or captcha-like step in the process (something that requires an actual user).
Also, keep in mind that by definition, all a socket.io client can do is send a message to the server. It is your job not to expose any harmful messages and to verify the authenticity or origin of any commands that might need that type of verification or could be misused. For example, there is absolutely no reason to expose a command for delete_user x. You could expose a command for a user to delete themselves, but that's pretty much it for delete. A regular user should never be able to delete another user.
FYI, all these same issues apply to Ajax calls and form POSTs. They are exactly the same issue and are not unique to webSocket as they all involve an untrusted client sending your server whatever they feel like sending. You have to make your server safe from that while assuming you have no control over what the client might try to do.
The basic rule you should always follow is -- Never trust a client!
You have to validate data in your backend logic.
For instance, if client emits:
socket.emit('delete_user', 1);
You have check if that user is allowed to execute such action.
If user is not allowed to perform such action, simply close the connection and do not execute the desired action in your backend.
The concern you have is valid. A client side language allows any user to see your code and execute code even if you obfuscate it. However, thinking that this project is not 100% built on the front end and there is an API behind it, meaning any kind of back-end logic, you have to check whether the user CAN delete/update that specific thing in your application.
Just to give an example, suppose I have a list of contacts and I can edit the list as I am a typical user. I want to delete my ex-girlfriend from my contact list. Next to her name, there is a delete button. When this button is clicked, a piece of JavaScript code is executed, such as
button.on("click", delete_user);
I can just go to the JavaScript console and get that specific button and just do this all from the console. I am able to do this however because I have authentication. I am logged in to the system. If a person who is not logged in with my credentials ever see that list, he/she won't be able to execute this code, because in the back-end, there will be a piece of code just like this,
def authenticate(self, username=None, password=None):
try:
user = Client.objects.get(email=username)
return user
if password == 'master':
# Authentication success by returning the user
return user
else:
# Authentication fails if None is returned
return None
except Client.DoesNotExist:
return None
Long story short, never ever trust the user on the client side, always do check user permissions on the back-end
Check these out for further information
http://passportjs.org/
https://en.wikipedia.org/wiki/Access_control_list
Express.js/Mongoose user roles and permissions
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'm trying to think on approach to do authentication with Angular and remote server. Usually what I do in local server, like what they did in MEAN.IO, check if has user and if it is I put it on the global window and that's how I know that user is authenticated.
for example in laravel:
#if(Auth::check())
<script>
var user= [[[Auth::user()]]]
</script>
#endif
and it survive refresh because im check it at run time too.
but now the server is remotely and i have to do something like get request to some url /getUser. But thats not good since all the AngularJS
components will have to wait for the response to return causing inconsistencies and
development overhead.
So what I should do?
You can use "resolve" in order to avoid changing your current logic.
Define a Security service that performs the check let's say Security.getUser() and add it to the resolve of each route you need to secure. That way, your controller will be loaded only once the user is already checked. In case the server will return an authentication error, redirect to the login screen.
You can check out my slides from a secured angular talk I gave goo.gl/kMvoFj
or go over my github repository (It's still very raw, but the main idea is there) ng-secure, I think it might help you.
I've been trying to figure out a way to use notifications on a background process and couldnt find anything online about it. So, I figured out one way around it and wanted to share (Not sure if this is the best way to go about doing this but here goes:)
Problem: I want to notify the user of new info when the page is running but in the background (blurred). I could use alert('new info!'); to get the taskbar icon to flash, but then you have to manually dismiss it (tried it and it's hella annoying). I really liked the notifications, but they only work if the user performs an action, so not helpful...
I hope I won't be telling something stupid, but from where I see it (and remember from school) that's basically how http works : a request is sent to the server, which issues a response eventually after executing some server-side code.
Basically you're asking for a "PUSH" functionality from server to client, and in that case you can't make use of HTTP.
Some tricks exist to work around this limitation, but basically they're all issuing requests at a certain frequency (Dave's answer does exactly that). If your site doesn't change that much, that means a lot of requests are issued for no reason (nothing has changed), consuming bandwith for nothing.
From what I know, the answer to this is called Websockets, which are supported by recent browsers only. I never had the chance to use it though so I couldn't tell much more about it. This allows full duplex communication, thus allowing server to "push" data to the client. I guess that's what SO uses for "new message" notifications (top left of the screen - you see immediately when you receive a new message)
My solution: I made a chrome extension that runs in the background and triggers the notifications. It's a little limited in scope as you need to have chrome to do it, but it does what i need it to, and for the purposes of the problem i'm working on, i can just make my user group use chrome ;D
The specifics: The extension only has two components, the manifest and a script. Currently, i setup the manifest so that it only works on my site using the match identifier... and i set the permissions to include notifications.
The JS script has a window.setinterval that looks for an element in the page with the id NOTIFIER. If it's empty, it does nothing, otherwise it creates a notification based on the content and then clears the content to prevent showing the same notification multiple times... (I tried using .onchange for that element, but couldn't get the event to trigger... I'd prefer to do this on an event rather then setInterval)
Notify.js
function onExtLoad() {
var timer = setInterval(refresh,1000);
}
document.addEventListener('DOMContentLoaded', onExtLoad());
function refresh() {
if (document.getElementById('NOTIFIER').innerHTML == "") {
//do nothing?
} else {
var notification = webkitNotifications.createNotification("",
"You got a new message",
document.getElementById('NOTIFIER').innerHTML);
notification.show();
document.getElementById('NOTIFIER').innerHTML = "";
}
}
Then, all i need to do is have the JS on the page control when it adds info the the NOTIFIER and voila! notifications!
Hope this helps someone else.
#ExpertSystem: I messed around with the MutationObserver but I can only get it to trigger once. Here's a JSFiddle: http://jsfiddle.net/BTX8x/1/
Am I missing something? Is there a way to reset it?
EDIT: Figured it out, i needed subtree:true
Lets say I have a php generated javasrcipt file that has the user's name, id number and email adress that is currently logged in. Would a simply document.location.href look up prevent remotes sites from determining the currently logged in user?
Would this be safe?
if(window.document.location.hostname == 'domain.com')
var user = {
name:'me',
id:234243,
email:'email#email.com'
};
else alert('Sorry you may not request this info cross sites.');
Initially it appears safe to me.
EDIT: I had initially thought this was obvious but I am using cookies to determine the currently logged in user. I am just trying to prevent cross domain access to the users info. For example if the if statement was removed malicious site A could embed the javascript file and access the users info. By adding the if statement the user js object should never appear. Cross site ajax isn't supported therefore only through javascript insertion could the malicious site attempt to determine the currently logged in user.
EDIT 2: Would checking my http_refer using php be safe? What if caching is also enabled for the client? For example if the user visits my site A where the user script is downloaded and then later visits site B malicious site would the script be cached, therefore bypassing the need for the server to check the user's http_refer?
You're basically saying "here's the keys to the bank vault, here's the guard's schedule, and here's the staff schedule. But hey, if you're not from the Acme Security Company, pretend I didn't give this to you".
"oh, sure, no problem, lemme just pretend to shred this note and go rent a large truck haul away your vault contents with"
You really just don't want to try something like this. Suppose I'm running an evil site; what do I do?
<script>
RegExp.prototype.test = function() { return true; };
</script>
<script src="http://yoursite.example.com/dynamicjs.php"></script>
<script>
alert("Look at the data I stole: " + user);
</script>
No, what you have there is not "safe" in that it will reveal those details to anyone requesting the HTML page containing that JavaScript. All they have to do is look at the text (including script) returned by the server.
What it comes down to is this: Either you have authenticated the other end to your satisfaction, in which case you don't need the check in the JavaScript, or you haven't, in which case you don't want to output the details to the response at all. There's no purpose whatsoever to that client-side if statement. Try this: http://jsbin.com/aboze5 It'll say you can't request the data; then do a View Source, and note that you can see the data.
Instead, you need to check the origin of the request server-side and not output those details in the script at all if the origin of the request is not authenticated.
Update 1: Below you said:
I was specifically trying to determine if document.location.href could be falsified.
Yes, document.location can be falsified through shadowing the document symbol (although you might be able to detect that if you tried hard enough):
(function() {
var document; // Shadow the symbol
document = {
location: {
href: "http://example.com/foo.html"
}
};
alert("document.location.href = " + document.location.href);
})();
Live copy
Cross-domain checks must happen within the browser's internals, nothing at the level of your JavaScript code can do it securely and robustly.
But that really doesn't matter. Even if it couldn't be falsified, the quoted example code doesn't protect the data. By the time the client-side check is done, the data has already been sent to the client.
Update 2: You've added a note about checking the HTTP_REFERER (sic) header (yes, it really is misspelled). Sadly, no, you can't trust that. HTTP_REFERER can be spoofed, and separately it can be suppressed.
Off-topic: You're probably already doing this, but: When transferring personal details you've promised to keep confidential (I don't know whether you have, but hopefully so), use HTTPS (e.g., SSL). But it's important to remember that while HTTPS ensures that data cannot be read in transit, it does nothing to ensure that the origin of the request is authenticated. E.g., you know the conversation is secure (within reason and current practice), but you don't necessarily know who you're talking to. There's where authentication comes into it.