I have an application which uses Backbone JS to render its views (among other things like models etc.).
Parts of my application should only be displayed to admin users, but the only way for Backbone templates to know this is for some JS variable/localStorage/Cookie to be set to indicate such.
The first worry here would, of course, be security. I am only really storing things like User.id, User.isAdmin etc. in here. Furthermore, since the only things limited to administrators would involve server-side involvement, changing User.isAdmin = true on the client side will just give them the interface options, but none of the power.
I know that using Cookies for this sort of thing is probably frowned upon, and with good reason, since Cookies are sent to and fro across all HTTP requests creating unnecessary overheads.
Therefore my question is, how best should I tell my client-side application about User authentication data. I am using jStorage (http://www.jstorage.info) for localStorage access, but it does not use SessionStorage. Would the latter be more appropriate than the former?
Speaking generally, you need roles and possibly privileges on the server. This way, even if a nefarious user tweaks the client, user cannot actually access or modify restricted data, because if they try, they still havent modified the role on the server. If you audit log access, you will know fairly quickly if a user tries something for which they don't have privileges.
The worst that can happen under a scheme like this is the user could see what the admin screens look like. This still might be a breach, since they might see buttons that could inform them how the system works.
If you need to protect that, you could delay the loading of the templates for the "Admin Section" of your app until after a users role has been verified. So all restricted sections are almost loaded as a separate app (or an actual separate app). That way, even if the user tries to fool the client to load the admin section, when the request goes to the server you don't return the module, since the server will not show the user as having admin privileges.
Related
I am working on a Meteor application that uses Iron Router. We have a login page in our application. Even when the user is not logged in, if I call the below code on developer console as un-authenticated user:
Router.routes
It gives all the routes and the respective paths. Is there a way to disable access to these paths or do I need to push these end points in the server code ?
Everything you define on the client is visible on the client. So is all the routes definitions and routes logic, too. In production code this will be obfuscated but it's still there.
If you are concerned, that clients can read your routes, then you should be more concerned about the fact that it concerns you. Sounds a bit confusing but the point is: you should double check each data published to client via publications or manipulated / created via methods on server. If your backend is robust and secured as much as possible (100% will never be possible), then you don't need to care, if clients can see which routes exist and get access to them.
An example:
Bob found the route /admin and disabled the router's triggers to redirect him if he is not Admin.
Now Bob could see all data, that Admins can see. To prevent this, you may check in the publication if Bob has the role 'admin' on don't publish to him if he's not admin.
Ada also found this way to the Admin panel and wants to create a new user. Because your server method for creating new users is a ValidatedMedthod that checks if Ava has the 'admin' role it will fail to create a new user, because Ava is not an admin.
Conclusion:
Preventing access on the client side is just UI Magic bot not secure at all. Simple tweaks, however on the server side will help you to sleep better.
More help:
A good way to get started is to read the Meteor Security Guide:
https://guide.meteor.com/security.html
There is also at the end a security checklist, which I just cite for completeness and SEO reasons here:
Make sure your app doesn’t have the insecure or autopublish packages.
Validate all Method and publication arguments, and include the audit-argument-checks to check this automatically.
Deny writes to the profile field on user documents.
Use Methods instead of client-side insert/update/remove and allow/deny.
Use specific selectors and filter fields in publications.
Don’t use raw HTML inclusion in Blaze unless you really know what you are doing.
Make sure secret API keys and passwords aren’t in your source code.
Secure the data, not the UI - redirecting away from a client-side route does nothing for security, it’s just a nice UX feature.
Don’t ever trust user IDs passed from the client. Use this.userId inside Methods and publications.
Set up browser policy, but know that not all browsers support it so it just provides an extra layer of security to users with modern
browsers.
Useful packages mentioned in the answer:
mdg:validated-method
alanning:roles
audit-argument-checks
I'm trying to make a user log in just once, and have his information on all the servers. Any changes made to the user's information will instantly be available for all servers. Is this possible to do without having each user "log in" separately for each server?
Sort of like the $_SESSION for php, but for Node.js
Design 1 -
What I think would be best to do, but don't know how to share socket data between servers, perhaps using something like PHP's $_SESSION?
Design 2 -
What I'm currently doing:
User uses socket.emit to main.js
main.js adds user information onto the emit
main.js emits to the appropriate server
Appropriate server emits back to main.js
main.js finally emits back to user
This seems awfully inefficient and feels wrong
If your information is primarily static, you can try something similar to JWT. These are cryptographically signed tokens that your authenticating server can provide and the user can carry around. This token may contain information about the user that you want each server to have available without having the user accessing it.
If it's not, you may be looking into sharing a database across all servers, and have that be the point of synchronization between them.
Updates based on our comments (so they can be removed later):
If you decide to use auto-contained JWT tokens, you don't need to be making trips to the database at all. These tokens will contain all the information required, but it will be transparent to the end user that won't have insight into their contents.
Also, once you understand the JWT standard, you don't necessarily have to work with JSON objects, since it is just the serialization approach that you can switch by another one.
You'd provide one of these tokens to your user on authentication (or whenever required), and then you'd require that user to provide that token to the other servers when requesting information or behavior from them. The token will become your synchronization approach.
It has been some time now that i am learning and using angularjs framework, and although some of it's features are truly awesome, it seems to me as if it's key features are a bit problematic for authentication based applications.
Let's look at an example. Let's say i have a website that has a user login, and once the user is logged in he can click on a link to his/hers dashboard page. On the dashboard the user can see some private data. Now, the way i'm used to do it, is run some script on the server side and then if a user is connected, return some HTML, if no then redirect the user to another location. The way angularjs encourages me to do it is by using the route feature, say like this:
when('/dashboard', {
templateUrl: 'dashboard.html',
controller: 'DashboardController'
})
This way, in case a user is not connected, angularjs will first fetch the template HTML, then the controller will fetch some data and receive an authentication error, then redirect the route to another location. To me it seems like a worse solution for more than one reason:
1) First of all, my HTML gets exposed to everyone. Although this isn't devastating, it just seems like a bad security practice (imagine that you do not even have a facebook account, but still you can see all of facebook pages HTML, and even worse, all the objects and fields of the like for example user.accessToken).
2) I would make a larger number of requests to the server, first one to fetch the template, second for authentication validation and data, third and probably fourth for the redirection. I assume angularjs cache the templates so maybe the actual number of requests is smaller than i mentioned, still, dealing with all this on the server side is only one request - and like angularjs, it can also not load the entire page but only the needed HTML throw AJAX. My case here is arguable, but still, something about it seems wrong.
3) This is maybe the most important issue for me. Everything i do on the server side has to be pasted on the client side. For example, the routing feature must be clear on the server side as will as on the client side - in case the user enters directly to some inner page in my application, or through routing in the application links. This means that every time a change something in my routing configuration, i have to do it once in the server side, and once in the client side - which also seems to me like a bad practice and modularity of my code.
Is angularjs not recommended for these kind of applications? Should i use angularjs features that complement my applications (like controllers, variable binding and so on) but disregard and ones that doesn't (like routing)?
Do i look at it the wrong way?
You aren't looking at it the wrong way, just from a different perspective. You aren't use to developing SPA's so this is normal.
1) Sure HTML gets exposed to everyone, but that is just a template. It just contains the html template, not the specific data related to everyones facebook profile. The server controls the data that is returned to the user and it would only return the data that the user had access to see. Really this is no different to a non SPA except for the amount of data that is sent back and forth.
2) For a normal app you would first have to request the login page, then the data would be posted to the server and then a redirect would occur. This is 3 requests. With angular it would be one for the first load, second for the login view template, then third to post login data, then fourth to get the main logged in view and fifth for data required for the view. This is only two more. After that to login, if the user clicks log out and then login again it would only be two requests vs three, or if they close the tab and come back it would be 3 requests. In other words it's not that much difference. For most scenarios it will be the same amount of requests, if not less after caching.
3) The way routing works in a SPA is it only happens on the client. There is no need to have it also on the server. Just re-write the url for all request to return index.html and then angular routing will take care of the rest.
In regards to it being recommended. There are really no such recommendations. It's up to you. There are advantages and disadvantages with both. Most of the disadvantages of Angular would be related to learning curve.
Yes, you do look at it the wrong way. You mix up client- and server side issues.
Your proposed solution for authentication is, as you already said so yourself, bad from a security point of view. Delivering your HTML to the user although he/she is not authenticated is a bad idea.
Authentication always has to be done on the server side. Do not ever trust the client. That's why when you have have an unauthenticated user requesting your restricted-access dashboard.html, you sent back some HTTP error (typically 401 or 403, depending whether the user is unauthenticated or not authorized). This way, an unauthenticated user will never see the dashboard.html and your problems 1 and 2 are solved.
Your point 3 is another matter, but also invalid. There is no reason why your client and server side should have the same routing features. Routing should be up to the client-side in most circumstances. E.g., if your user manually enters http:://mydomain.org/subsite, the server redirects him to http:://mydomain.org, where AngularJS uses the appropriate routing.
So your points are not really about AngularJS being a problem for applications requiring authentication. As a matter of fact, there are many web apps out there with authentication using AngularJS. So as conclusion: No, you can use AngularJS as much as any other JavaScript technology for authenticated sites. However, if it is "recommended" (for your project) is another matter, which depends on many more factors and is beyond the scope of SO.
I've read about Firebase and it looks awesome for what I want to do.
I've read about authentication and how based on rules certain logged-in users are authorized to do different stuff. Al good.
However, I'm unsure about another type of security: how do I make sure that only my own site (using client-side javascript) can talk to my firebase-backend? I'm asking because afaik there's no way to prevent anyone from looking up my firebase endpoint from the client-side code (url pointing to my specific firebase backend) and start using that for god knows what.
This is especially worrisome in situations in which I want to open up writes to the anonymous user role. (e.g: some analytics perhaps)
Any help in clearing my mind on this much appreciated.
Update (May 2021): Thanks to the new feature called Firebase App Check, it is now actually possible to limit calls to your backend service to only those requests coming from iOS, Android and Web apps that are registered in your Firebase project.
You'll typically want to combine this with the user authentication based security that Kato describes below, so that you have another shield against abusive users that do use your app.
In my opinion, this isn't so much a question about Firebase's security as a general discussion of the internet architecture as it stands today. Since the web is an open platform, you can't prevent anyone from visiting a URL (including to your Firebase) any more than you can prevent someone from driving past your house in the real world. If you could, a visitor could still lie about the site of origin and there is no way to stop this either.
Secure your data with authentication. Use the Authorized Domains in Forge to prevent CSRF. Put security rules in place to prevent users from doing things they should not. Most data writes you would use a server to prevent can be accomplished with security rules alone.
This is actually one of the finer qualities of Firebase and API services in general. The client is completely isolated and thus easily replaced or extended. As long as you can prove you're allowed in, and follow the rules, where you call in from is unimportant.
Regarding anonymous access, if you could make them visit only from your site, that still won't stop malicious writes (I can open my JavaScript debugger and write as many times as I want while sitting on your site). Instead, place tight security rules on the format, content, and length of data writable by anonymous users, or save yourself some time and find an existing service to handle your analytics for you, like the ubiquitous Google Analytics.
You can, of course, use a server as an intermediary as you would with any data store. This is useful for some advanced kinds of logic that can't be enforced by security rules or trusted to an authenticated user (like advanced game mechanics). But even if you hide Firebase (or any database or service) behind a server to prevent access, the server will still have an API and still face all the same challenges of identifying clients' origins, as long as it's on the web.
Another alternative to anonymous access is to use custom login, which would allow a server to create its own Firebase access tokens (a user wouldn't necessarily have to authenticate for this; the signing of the tokens is completely up to you). This is advantageous because, if the anonymous user misbehaves, the access token can then be revoked (by storing a value in Firebase which is used by the security rules to enforce access).
UPDATE
Firebase now has anonymous authentication built into simple login, no need to use custom login for common use cases here.
I am attempting to develop a pure javascript web application using Dojo. The problem I face is one of restricting access to portions of the application. Authenticated users should be able to access everything, whereas non authenticated users should only be able to access a login screen.
The issue is that nothing (that I am aware of) will stop a user from opening up a browser javascript terminal and entering something like: app.displayRestrictedContent(); and thus gaining access to a screen intended for authenticated users.
I have implemented an ajax based login; all ajax calls are secured with a session. So while the non-authenticated user can load a restricted screen, they wont be able to fetch data for it. But still, It seems wrong for this screen to be arbitrarily accessible.
Am I trying to do the impossible? It seems silly to write code such as if (user.auth) app.displayRestrictedContent(); when it's so easily circumvented. And this leads me to believe I am missing something rather obvious to everybody else. I can't find much information at all on pure javascript based apps and authentication models.
But still, It seems wrong for this screen to be arbitrarily accessible.
Because it's client-side code. Anything you write in js, or get compiled to js, expect it to be readable by the users.
Am I trying to do the impossible?
you can dynamically load js modules after the user authenticates. So at first, just load 1 login module. When the user logins, if successful, the server return a list of js modules to load, if not, return empty list. It also helps improve load time when the users come to your website.
I'm by no means an expert, but here are some thoughts I've made on this. I don't think you've missed anything (if so, I have too) - I think this is a pretty fundamental issue with all client applications, whether it's a compiled executable or a Javascript.
Of course, the compiled executable is not particularly hampered by it, because it's been made into machine code which is very difficult to read or decompile into anything useful. With Javascript however, the application is often served exactly as you wrote it, and so it's easy to modify and reason about.
That brings me to the first semi-solution: obfuscating your Javascript. If you use Dojo's build tool with the shrinksafe parameter, all unnecessary whitespace is removed and all identifiers are shortened, making the code quite difficult to read. I called this a semi-solution, some may say even that is giving it too much credit - I myself still think it's worth doing. After all, the shrunk code downloads faster too!
The second measure I take in my apps is to separate the different parts into "build layers". For example, in my build profile, I'll have something like
dependencies = {
..
layers: [
{ name: "../myApp/Core.js", resourceName: "myApp.Core",
dependencies: ["myApp.Core", "myApp.Foobar"]
},
{ name: "../myApp/modules/Login.js", resourceName: "myApp.modules.Login",
dependencies: ["myApp.modules.Login", "myApp.modules.LoginUi"...],
layerDependencies: ["../myApp/Core.js"]
},
{ name: "../myApp/modules/Secret.js", resourceName: "myApp.modules.Secret",
dependencies: ["myApp.modules.Secret", "myApp.modules.SecretUi"],
layerDependencies: ["../myApp/Core.js"],
authentication: 42
}
]
}
Now, instead of serving the built JS files directly as static files, I let the requests go through a controller in my server-side application, which checks if the JS layer requires authentication and whether or not the user is logged in with the necessary access.
This does have certain cons. The JS files aren't cached, and if I had all my JS in one build layer, the application would probably load slightly faster. There's of course also a limit to how nuanced it's worthwhile to make the layers. More layers mean more hassle, but also more finely grained module access.
I'd be interested to hear others chime in on this as well. It's a good question.
When a user successfully logins the server should provide him with a session token. The Afterwards, whenever the user requests a resource (either via just redirecting the browser or via AJAX) he shows the server his session token (either by storing it in a cookie and sending it automatically on all requests or by explicitely passing it in the body of an AJAX request)
The server can then use session tokens from the users to control authorizations server-side, rejecting any request with an invalid or outdated token.
https://en.wikipedia.org/wiki/HTTP_cookie#Session_management