What is the standard practice in Meteor for controlling users access for certain sensitive pages? For example, only users with Admin level can access CRUD operations, so what is the best method to block/allow users access these pages?
I know that we can use publish to limit the user accessibility to data, but for pages, what is the best way?
I am thinking of checking the user level during the rendered but again, I am not sure if this method is safe.
There is currently no method of denying access to a page, as the whole client code is packed and sent as one application. Since the code for restricted page is in the browser, user can access the page easily.
What you can do is to restrict access to data displayed on those pages. There are two things to be done:
Specify what data the user can see. This is done via the publish and subscribe methods. In the Meteor.publish method you can check user privileges and decide which objects user can see, and which fields of those objects.
Specify what data the user can change. This, as stated in the other answer, is achieved by Collection.allow and Collection.deny methods, which allow you to check user privileges on each CRUD operation and decide whether it's allowed.
The only places you need to control the user's level are in publish and in allow/deny callbacks. By controlling it in publish, you make sure the user does not receive any information it shouldn't know, and by controlling it in allow/deny callbacks, you make sure the user does not add/edit/delete information it's not allowed to.
If you're using custom methods for CRUD operations (on the server), this is a third place where you need to control the user's level (allow/deny callbacks are only checked against CUD operations made on the clients!).
Edit
For examples on how to use the allow callback, see http://docs.meteor.com/#allow The deny callback works in a similar (but opposite) way. At least one allow callback must return true and all deny callbacks must return false in order for operation to be granted.
Related
I want to implement authorization in AngularJS. In my project which is some kind of social media, different roles or even same roles may see a view file differently.
For example imagine we have two different roles: customer and company.
A customer and a company may have different things in a shared view file, for example a company can have rate on his profile while a customer can't. (different roles).
Or a customer may see a button in a page while another customer can't. (same roles)
As you can see I can't implement authorization by simply checking the roles, and in some situations I need to communicate to the server.
I have multiple choices:
Create a variable in my controller's scope with corresponding permissions, which they have default value of false:
$scope.auth = {
canRate: false,
isConnected: false
};
Then connect to server and change the value of auth object based on the response. And use ng-if in my view files to show or hide elements.
Create a directive and pass comma-separated permissions to it.
<button auth="canRate,isConnected"></button>
Then connect to server to check the permissions. If all of them where true, then show the element.
Use resolve: {...} and get all necessary data from the server when routing, which increases loading time of each page.
I want to know is there a better approach to solve this problem?
Any kind of help or comment would be greatly appreciated.
Note: Of course I have server side authentication and authorization! I just want to show some elements in a view file based on user roles or some other conditions which I explained. And this elements are something like a button or a link, otherwise instead of using a shared view and hiding elements, I could use different views for each situation.
Any how, I know this approaches are for display purposes only, and they can not solve security challenges.
First things first, I LOVE AngularJS. But, like all web client frameworks, in a strict sense you can't implement Authorization in AngularJS.
You can not trust the web client to hide data from the user. If the server sends the data to the client, they can still find a way to see it (using fiddler for example) even if you use ng-hide to avoid displaying it.
So, you must implement Authorization on the server side. Now then, assuming you do that:
AngularJS is great for building dynamic web interfaces based on the data you receive from the server. So, your server should only send the data your client is allowed to see. Then, you can use ng-hide or ng-if to avoid displaying the components that would otherwise show that data.
Furthermore, your server can even send an object that contains the list of possible actions available to the user. And then you could use ng-hide in your buttons so as not to show them when the action isn't available.
Even still, you will need to code your server side to ignore actions that the user isn't allowed to take.
Your approach will work, but it is not secure. I would make sure that the server handles the authentication as well. Personally, I've always used a server-side token based authentication system when working with AngularJS.
Instead of using ng-if, you should make your GET or POST requests require the token given on login. From there the server can determine whether or not to allow the request to succeed, with no chance of the user faking credentials. Both of your examples work fine, but use them as a means to hide things for display purposes only. The web client will NOT keep sensitive information safe or prevent the possibility of POST requests from unwanted users.
I am using the Azure Application Insights JavaScript library to keep track of some business flow in my application. AppInsights uses a session_id (saved to a cookie) to connect separate events into a flow. This value is automatically generated and managed.
The problem is that now the business flow requires me to track events from multiple domains. Can I somehow tell AppInsights-JS that I want to continue a previous session? If the current session could be serialized into a string, and loaded on an other page, that would be perfect, I could just pass it along as a query parameter to the page on the other domain.
My first thought was to save the ai_user and ai_session cookie values, but it feels like hacking the system.
The solution I am currently using is to maintain a custom sessionid myself, and pass it to every tracked event as a custom dimension. This way I can filter the events based on this field to obtain the events of a business flow. It's a bit harder to use this way.
Is it safe to just save and store the cookie values? Or is there any better way to do this?
JavaScript SDK doesn't support this functionality today. But you can write a TelemetryInitializer to override the ai_session and ai_user.
In Laravel, you can restrict access to some Controllers (eg. Admin-related controllers such as Admin/UsersController, Admin/SettingsController, etc.) to specific user sessions. Because it's server-side, the user has no-way to snoop-out about such controllers unless authenticated.
In the case of AngularJs's, the code resides in the browser. Thus, anyone can get a look at the javascript source codes and might figure-out the behaviour of the app. Say he might discover that there are controllers that manage admin-related data. Or anyone might try to brute-force-search the app's URL for javascript files to observe. Say he looks at http://myapp.com/AdminSettingsController.js in which authenticated users should only be able to see or should not at all.
Going back to the main question, how do you resolve such issues?
This problem has only one solution. Treat JavaScript as language for your User Interface only. Nothing more than that. Don't store any sensitive data in browser, don't store any sensitive logic (e.g. database queries) either. There is no way to hide network traffic or source code from client.
I usually create some sort of user object on client side, which contains users role for resolving permissions, and I use the permission for display controls, e.g. show some buttons only to admin etc. BUT, this only affects the displaying of the page, If user interacts with that controls, the controls rely on the server and if the user does not have proper permissions on the server as well, the interaction with the control fails, so if anyone with some knowledge change the user object on the client and grants him administrator role, he only sees the control what the administrator would see, but he can not make administrator actions nor he sees any sensitive data.
I'm setting up parse framework in javascript. I notice that I need to call
Parse.initialize("app", "secret")
Since this is in the page source, couldn't anyone take this and make calls against my account?
Is there a more secure way to store this info?
As per Parse Security Guide your JavaScript key is NOT secret:
When an app first connects to Parse, it identifies itself with an Application ID and a Client key (or REST Key, or .NET Key, or JavaScript Key, depending on which platform you're using). These are not secret and by themselves they do not secure an app. These keys are shipped as a part of your app, and anyone can decompile your app or proxy network traffic from their device to find your client key. This exploit is even easier with JavaScript — one can simply "view source" in the browser and immediately find your client key.
So yes, anyone who found your key can make calls.
But you can (and should) restrict what such anyone can do.
Using Class-Level Permissions you restrict what can be done with individual classes.
Using Object-Level Permissions you restrict what can be done with selected objects.
See also Roles and Roles Hierarchy for simultaneously setting permissions for a group of several users.
For instance, you can restrict access to only specific users. Only if one of those users is logged in, the access is granted. Any other "hacker" can try to use your keys but the request will be rejected by Parse.
I'm trying to write a javascript single-page-app that allows users to login and then, once logged in, create/modify records in a database. I'd like to avoid having my own server side scripts if possible, instead using something like Parse.com, Kinvey.com, or Cloudmine.me.
My issue is that these services have user login capacity but use API keys to determine whether your app has write access. They don't seem to let you have write access once your user is logged in. The only way I can think of to accomplish this is to store a write-access API key in the user's user data, so I'd have the user login, fetch the hidden API key, then change the API key of the app to use that one, so they'll have write access. Obviously this isn't very secure because once that API key is sent over the network, that user will have write-access even if we delete their account or they change their password.
Perhaps I'm going about this the wrong way, so feel free to let me know. Hopefully this made sense. Thanks!
You should be able to restrict access to a group of users using Parse.ACL: http://www.parse.com/docs/js/symbols/Parse.ACL.html
If you want to control access on a per user basis then you will have to maintain a custom property on the user object. Then you can check the custom property in the BeforeSaveRequest() function and decide whether the user has write access: http://www.parse.com/docs/js/symbols/Parse.Cloud.BeforeSaveRequest.html
By default, most BaaS providers should provide collection level security and some even offer per entry security via ACL's (Access Control Lists).
Kinvey for instance has several variations on collection level security:
http://devcenter.kinvey.com/html5/guides/security#Collectionlevelpermissions
The default security level of Shared make it so the user has access to read everything in the collection but can only write to their own items. You may also want to use the Private security level to make it so you can only read and write to your own items.
If you want to have more fine-grained control over security you can utilize entry level permissions:
http://devcenter.kinvey.com/html5/guides/security#Entitylevelpermissions
With entry level permissions you can give fine grained access to a specific user or groups of users that you manage. You can even determine what level of security a user has to your entry, read or write. If you have a need to go even finer with control you have full access to write your own security utilizing Business Logic.
Full Disclosure - I am an engineer at Kinvey.