Meteor: SSR necessary to secure admin part of application? - security

I have my extended user model in the Meteor.users collection, which I'm publishing most fields from to the client. Each user has an isAdmin field, set to false by default.
Now I have two concerns, which are linked:
How to make sure, components meant for admins can only be rendered, if the isAdmin field in the Meteor.users collection is set to true?
How to make sure, the isAdmin field on the Meteor.users collection cannot be modified from the clients console?
Concerning 1.
I'm hesitant to publish this field to the client and simply evaluate isAdmin on the client side.
I'm not sure if there is some hackish way through the console to simply change isAdmin in a way that would allow to render the component (or part of it) that is only meant for admins on the client. I could imagine that it is possible with Object.defineProperty() to do so, for example.
Should I use server-side rendering to secure the admin part of my UI?
Concerning 2.
Consider the first paragraph on Profile editing in this article about common mistakes. It suggests that isAdmin could easily be changed from the client by calling Meteor.users.update(Meteor.userId(), {$set: {'isAdmin': true}}) from the console.
When I run it, being logged in to my application, I get update failed: Access denied though.
But even the official documentation still suggests to add
// Deny all client-side updates on the Lists collection
Lists.deny({
insert() { return true; },
update() { return true; },
remove() { return true; },
});
at https://guide.meteor.com/security.html#allow-deny
There is an answer, suggesting that it's enough to simply check for the isAdmin property on the server side, if you make sure that the Meteor.methods are server-only. But it doesn't talk about allow-deny at all and it's 6 years old.
Can anyone tell, what truly is the case as of today?

Can anyone tell, what truly is the case as of today?
I would not put too much effort to secure the admin ui on the client. A router level redirect when isAdmin is false should be sufficient.*
Way more important here is to secure methods and publications because these are the parts where users can mess around with your application. For those it can't be secure enough:
use ValidatedMethod from mdg:validated-methods for Methods
write a factory function to create Publications similar to mdg:validated-method to allow basic checks in a mixin-style
both: check if the arguments are valid
both: check if the user exists
both: check if the user has sufficient roles -> I recomment alanning:roles as it makes permission level checks more secure as it checks for id-match existence in a dedicated collection rather than checking for a flag in the user collection (plus it decouples the users from the roles!)
Throw fast and a lot: throw on any suspicious inconsistency, try to cover any undefined state with throwing errors.
rate limit using ddp-rate-limiter every method and publication
write a simple sanity check on startup that ensures all methods and publications are rate-limited, you can get all registered methods/publications on the server at Meteor.startup via Meteor.server.method_handlers and Meteor.server.publish_handlers
write test a lot, especially for the admin related methods and try any weird and crazy input you can think of to see if it gets rejected or causes any weird behavior (which you want to avoid)
As far as I understood your question you have currently not integrated ssr and if you follow the above steps you can secure your admin-area of the application a lot without including ssr into your app (which itself can cause a lot of headache due to additional config etc.).
*if you decide to use the recommended alanning:roles package you would be better to also use it on the client to check the user's roles.

Related

CQRS and cross cutting concerns like ABAC for authorization reasons

Let's assume a monolithic web service. The architectural design is based on the DDD and divides the domain into sub-domains. These are structured according to the CQRS pattern. If a request arrives via the presentation layer, in this case a RESTful interface, the controller generates a corresponding command and executes it via the command bus.
So far so good. The problem now is that certain commands may only be executed by certain users, so access control must take place. In a three-layer architecture, this can be solved relatively easily using ABAC. However, to be able to use ABAC, the domain resource must be loaded and known. The authentication is taken over by the respective technology of the presentation layer and the authenticated user is stored in the request. For example, JWT Bearer Tokens using Passport.js for the RESTful interface.
Approach #1: Access Control as part of the command handler
Since the command handler has access to the repository and the aggregate has to be loaded from the database anyway in order to execute the command, my first approach was to transfer access control to the command handler based on ABAC. In case of a successful execution it returns nothing as usual, if access is denied an exception is thrown.
// change-last-name.handler.ts
async execute(command: ChangeUserLastNameCommand): Promise<void> {
const user = await this._userRepository.findByUsername(command.username);
if (!user) {
throw new DataNotFoundException('Resource not found');
}
const authenticatedUser = null; // Get authenticated user from somewhere
// Handle ABAC
if(authenticatedUser.username !== user.username) {
throw new Error();
}
user.changeLastName(command.lastName);
await this._userRepository.save(user);
user.commit();
}
However, this approach seems very unclean to me. Problem: In my opinion, access control shouldn't be the responsibility of a single command handler, should it? Especially since it is difficult to get the authenticated user or the request, containing the authenticated user, at this level. The command handler should work for all possible technologies of the presentation layer (e.g. gRPC, RESTful, WebSockets, etc.).
Approach #2: Access control as part of the presentation layer or using AOP
A clean approach for me is to take the access control from the handler and carry it out before executing the command. Either by calling it up manually in the presentation layer, for example by using an AccessControlService which implements the business security rules, or by non-invasive programming using AOP, whereby the aspect could also use the AccessControlService.
The problem here is that the presentation layer does not have any attributes of the aggregate. For ABAC, the aggregate would first have to be loaded using the query bus. An ABAC could then be carried out in the presentation layer, for example in the RESTful controller.
That's basically a good approach for me. The access control is the responsibility of the presentation layer, or if necessary an aspect (AOP), and the business logic (domain + CQRS) are decoupled. Problem: The main problem here is that redundancies can arise from the database point of view. For the ABAC, the aggregate must be preloaded via query in order to be able to decide whether the command may be executed. If the command is allowed to be executed, it can happen that it loads exactly the same aggregate from the database again, this time simply to make the change, even though the aggregate has already been loaded shortly before.
Question: Any suggestions or suggestions for improvement? I tried to find what I was looking for in the literature, which was not very informative. I came across the following Security in Domain-Driven Design by Michiel Uithol, which gives a good overview but did not answer my problems. How do I address security concerns in a CQRS architecture? Or are the redundant database access negligible and I actually already have the solution?
I would handle authentication and the overall authorization in the infrastructure, before it reaches the command handlers, because it is a separate concern.
It is also important to handle authentication separately from authorization, because there are separate concerns. It can become pretty messy if you handle authentication and authorization at the same time.
Then you I would do final authorization in the handler (if needed), for example if you have a command AddProductToCart, then I would make sure that the user who initially created the cart-aggreagate is the same as the one making the AddProductToCart command.

Sensitive Data in Vue Data Property

I've been learning Vue for the past month or so but one question still eludes me:
The web app I'm building allows users to collect daily diaries for various projects, so they can switch from one project to another an edit the relevant diaries.
With role based authentication in mind (not implemented yet) I plan to load the first project the user has access to as the entry point to the app. I'd do this by fetching the first project they have access to from the API and store it as a data property in App.vue like so:
data: ({
appState: {
projectCode: "1298BAX",
projectName: "Learning JavaScript 2020",
availableProjects: ["Learn Node", "Learn Express"],
company: [],
},
}),
The 'appState' object dictates which diaries the app should load by referencing the 'projectCode' property when fetching diaries from the API. And if the user switched to a different project e.g. "Learn Node" then the new appState would be:
data: ({
appState: {
projectCode: "444444",
projectName: "Learn Node",
availableProjects: ["Learning JavaScript 2020", "Learn Express"],
company: [],
},
}),
Now the user can fetch the "Learn Node" diaries when they navigate to the list of diaries they can edit.
My concern is that, this isn't a secure pattern. Is storing such data which will be used in API calls safe in the data property? Would this be a security issue or is it typically safe to do it this way?
I welcome your constructive feedback and suggestions. I apologise for my ignorance but as a solo dev learning without an experienced dev, theoretical questions like this are hard to solve when Googling lets you down :(
No data is safe once its in the browser. Only solution is to always check user privileges on the server side...
Don't trust anything coming from the browser :)
This is not a Vue question so everything I say here applies to anywhere else on the web. When it comes to securing your website take this simple rule and run with this:
Nothing in the front-end it secured.
And I mean nothing. Even if you put Auth Guards on it, and more stuff like that, if the information is stored inside JavaScript files, they are available for anyone to see.
The only way to truly secure something is by having the server serve it to the client. The serve code is not visible to the client, that's why you can do whatever you want there.
You do want to implement a system of authentication though, I recommend using a ready system like Auth0, JWT Tokens, or Firebase and not setting this up completely from scratch on your own.
In essence the reason why it's secure when using these systems is that each user has a unique ID that can't be guessed by anyone, or a unique token, and when the user makes the request to the server with the ID/Token only then the user can access sensitive information from the data-base, and only where this user's specific information is stored.
So if user x can only get the information that's associated with user x and user y can only get the information that's associated to him.
If anyone tries to make an API call and get some information, he will only be able to get his own information, never someone else's because the authentication and ID/Token comparison happens in the backend and like I said, trying to guess the unique UID is virtually impossible because it's so unique. (Also a lot of systems will block attempts to fake it)

How to allow only one user to register with Stormpath

Context: I have never work with Stormpath before and want to fully learn how to do certain stuff. To practice I'm creating my own portfolio, including the CMS.
My question is, how can I restrict the registration of accounts to a handful of specific emails using Google API (only me should be able to add and remove content from my own portfolio).
E.g. Allow ONLY example1#gmail.com and example2#gmail.com to register.
I could do it manually, but I do not want to do that. Steps I would like to follow are:
Specify emails
User tries to access the CMS
User is prompted to login or register
Only if user is in the specified list of emails, user can register using Google's API.
I do understand this is a very general question that involves several fields: Google's API, Stormpath, not to mention Express and Node, but maybe someone else solved this problem and I can see some code. Thanks.
I'm the author of the express-stormpath library which I'm assuming you're using. There's nothing out-of-the-box that does this, so I'd like to point out the best way to do this:
Create a custom registration route, and model it after the built-in stuff here: https://github.com/stormpath/stormpath-express/blob/master/lib/controllers.js#L143
In your custom registration route code, add in some code that checks to see if the email address supplied by the user is a valid one or not.
If not, reject their request.
Now, in the real world you probably wouldn't want to do this sort of thing (it's a lot of extra work, and doesn't buy you much). What you'd probably want to do instead is: completely disable account registration on your website. This way, only YOU can create an account using the Stormpath dashboard on https://stormpath.com, but login still works on your site so that you can log in.
Does that make sense?
So basically, what I'm suggesting is that you disable registration on your site by saying:
app.use(stormpath.init(app, {
enableRegistration: false, // this will disable the registration page / functionality
// ...
}));
Hopefully this helps =)

Why doesn't unlockedActions override requireAuth in CakePHP?

In my Cake 2.3 app, I have an action that's called via ajax. Since I'm using the Security component, I had to use $this->Security->unlockedActions, otherwise the action would fail.
However, unlockActions doesn't work when $this->Security->requireAuth() is called. Is this a bug? Do I have a misunderstanding of how CakePHP handles security?
Why doesn't unlockActions override requireAuth?
SecurityComponent::requireAuth() adds that action to an array of required actions, stored in SecurityComponent::$requireAuth.
If you take a look at the Security Component's startup code, you'll find that SecurityComponent::_authRequired(), the method that checks the $requireAuth array, is called before the unlocked actions are even checked. I imagine if you require an action to be authorized, that should take precedence over telling the app that it doesn't.
I would still consider this a bug (or incorrectly documented), as it clearly states in the documentation:
There may be cases where you want to disable all security checks for
an action (ex. ajax request). You may "unlock" these actions by
listing them in $this->Security->unlockedActions in your beforeFilter.
This is a new feature so it might be good to open up a ticket explaining the confusion and see what the core team thinks about it.
I should also note here that disabling the Security Component for ajax requests isn't always necessary. I have several apps that successfully use the Security Component, along with CSRF checks, side-by-side with ajax.
Authentication is very different from security.
Security protects against several ways to hack into your website, while the auth components handles the clearance of your users. When a member is updating his profile, I do want to verify that it is a logged in member (authentication), but i might not want to use the security component for the action he is calling.

CQRS Event Sourcing: Validate UserName uniqueness

Let's take a simple "Account Registration" example, here is the flow:
User visit the website
Click the "Register" button and fill out the form, click the "Save" button
MVC Controller: Validate UserName uniqueness by reading from ReadModel
RegisterCommand: Validate UserName uniqueness again (here is the question)
Of course, we can validate UserName uniqueness by reading from ReadModel in the MVC controller to improve performance and user experience. However, we still need to validate the uniqueness again in RegisterCommand, and obviously, we should NOT access ReadModel in Commands.
If we do not use Event Sourcing, we can query the domain model, so that's not a problem. But if we're using Event Sourcing, we are not able to query the domain model, so how can we validate UserName uniqueness in RegisterCommand?
Notice: User class has an Id property, and UserName is not the key property of the User class. We can only get the domain object by Id when using event sourcing.
BTW: In the requirement, if the entered UserName is already taken, the website should show the error message "Sorry, the user name XXX is not available" to the visitor. It's not acceptable to show a message, that says, "We are creating your account, please wait, we will send the registration result to you via Email later", to the visitor.
Any ideas? Many thanks!
[UPDATE]
A more complex example:
Requirement:
When placing an order, the system should check the client's ordering history, if he is a valuable client (if the client placed at least 10 orders per month in the last year, he is valuable), we make 10% off to the order.
Implementation:
We create PlaceOrderCommand, and in the command, we need to query the ordering history to see if the client is valuable. But how can we do that? We shouldn't access ReadModel in command! As Mikael said, we can use compensating commands in the account registration example, but if we also use that in this ordering example, it would be too complex, and the code might be too difficult to maintain.
If you validate the username using the read model before you send the command, we are talking about a race condition window of a couple of hundred milliseconds where a real race condition can happen, which in my system is not handled. It is just too unlikely to happen compared to the cost of dealing with it.
However, if you feel you must handle it for some reason or if you just feel you want to know how to master such a case, here is one way:
You shouldn't access the read model from the command handler nor the domain when using event sourcing. However, what you could do is to use a domain service that would listen to the UserRegistered event in which you access the read model again and check whether the username still isn't a duplicate. Of course you need to use the UserGuid here as well as your read model might have been updated with the user you just created. If there is a duplicate found, you have the chance of sending compensating commands such as changing the username and notifying the user that the username was taken.
That is one approach to the problem.
As you probably can see, it is not possible to do this in a synchronous request-response manner. To solve that, we are using SignalR to update the UI whenever there is something we want to push to the client (if they are still connected, that is). What we do is that we let the web client subscribe to events that contain information that is useful for the client to see immediately.
Update
For the more complex case:
I would say the order placement is less complex, since you can use the read model to find out if the client is valuable before you send the command. Actually, you could query that when you load the order form since you probably want to show the client that they'll get the 10% off before they place the order. Just add a discount to the PlaceOrderCommand and perhaps a reason for the discount, so that you can track why you are cutting profits.
But then again, if you really need to calculate the discount after the order was places for some reason, again use a domain service that would listen to OrderPlacedEvent and the "compensating" command in this case would probably be a DiscountOrderCommand or something. That command would affect the Order Aggregate root and the information could be propagated to your read models.
For the duplicate username case:
You could send a ChangeUsernameCommand as the compensating command from the domain service. Or even something more specific, that would describe the reason why the username changed which also could result in the creation of an event that the web client could subscribe to so that you can let the user see that the username was a duplicate.
In the domain service context I would say that you also have the possibility to use other means to notify the user, such like sending an email which could be useful since you cannot know if the user is still connected. Maybe that notification functionality could be initiated by the very same event that the web client is subscribing to.
When it comes to SignalR, I use a SignalR Hub that the users connects to when they load a certain form. I use the SignalR Group functionality which allows me to create a group which I name the value of the Guid I send in the command. This could be the userGuid in your case. Then I have Eventhandler that subscribe to events that could be useful for the client and when an event arrives I can invoke a javascript function on all clients in the SignalR Group (which in this case would be only the one client creating the duplicate username in your case). I know it sounds complex, but it really isn't. I had it all set up in an afternoon. There are great docs and examples on the SignalR Github page.
I think you are yet to have the mindset shift to eventual consistency and the nature of event sourcing. I had the same problem. Specifically I refused to accept that you should trust commands from the client that, using your example, say "Place this order with 10% discount" without the domain validating that the discount should go ahead. One thing that really hit home for me was something that Udi himself said to me (check the comments of the accepted answer).
Basically I came to realise that there is no reason not to trust the client; everything on the read side has been produced from the domain model, so there is no reason not to accept the commands. Whatever in the read side that says the customer qualifies for discount has been put there by the domain.
BTW: In the requirement, if the entered UserName is already taken, the website should show error message "Sorry, the user name XXX is not available" to the visitor. It's not acceptable to show a message, say, "We are creating your account, please wait, we will send the registration result to you via Email later", to the visitor.
If you are going to adopt event sourcing & eventual consistency, you will need to accept that sometimes it will not be possible to show error messages instantly after submitting a command. With the unique username example the chances of this happening are so slim (given that you check the read side before sending the command) its not worth worrying about too much, but a subsequent notification would need to be sent for this scenario, or perhaps ask them for a different username the next time they log on. The great thing about these scenarios is that it gets you thinking about business value & what's really important.
UPDATE : Oct 2015
Just wanted to add, that in actual fact, where public facing websites are concerned - indicating that an email is already taken is actually against security best practices. Instead, the registration should appear to have gone through successfully informing the user that a verification email has been sent, but in the case where the username exists, the email should inform them of this and prompt them to login or reset their password. Although this only works when using email addresses as the username, which I think is advisable for this reason.
There is nothing wrong with creating some immediately consistent read models (e.g. not over a distributed network) that get updated in the same transaction as the command.
Having read models be eventually consistent over a distributed network helps support scaling of the read model for heavy reading systems. But there's nothing to say you can't have a domain specific read model thats immediately consistent.
The immediately consistent read model is only ever used to check data before issuing a command, you should never use it for directly displaying read data to a user (i.e. from a GET web request or similar). Use eventually consistent, scaleable read models for that.
About uniqueness, I implemented the following:
A first command like "StartUserRegistration". UserAggregate would be created no matter if user is unique or not, but with a status of RegistrationRequested.
On "UserRegistrationStarted" an asynchronous message would be sent to a stateless service "UsernamesRegistry". would be something like "RegisterName".
Service would try to update (no queries, "tell don't ask") table which would include a unique constraint.
If successful, service would reply with another message (asynchronously), with a sort of authorization "UsernameRegistration", stating that username was successfully registered. You can include some requestId to keep track in case of concurrent competence (unlikely).
The issuer of the above message has now an authorization that the name was registered by itself so now can safely mark the UserRegistration aggregate as successful. Otherwise, mark as discarded.
Wrapping up:
This approach involves no queries.
User registration would be always created with no validation.
Process for confirmation would involve two asynchronous messages and one db insertion. The table is not part of a read model, but of a service.
Finally, one asynchronous command to confirm that User is valid.
At this point, a denormaliser could react to a UserRegistrationConfirmed event and create a read model for the user.
Like many others when implementing a event sourced based system we encountered the uniqueness problem.
At first I was a supporter of letting the client access the query side before sending a command in order to find out if a username is unique or not. But then I came to see that having a back-end that has zero validation on uniqueness is a bad idea. Why enforce anything at all when it's possible to post a command that would corrupt the system ? A back-end should validate all it's input else you're open for inconsistent data.
What we did was create an index table at the command side. For example, in the simple case of a username that needs to be unique, just create a user_name_index table containing the field(s) that need to be unique. Now the command side is able to query a username's uniqueness. After the command has been executed it's safe to store the new username in the index.
Something like that could also work for the Order discount problem.
The benefits are that your command back-end properly validates all input so no inconsistent data could be stored.
A downside might be that you need an extra query for each uniqueness constraint and you are enforcing extra complexity.
I think for such cases, we can use a mechanism like "advisory lock with expiration".
Sample execution:
Check username exists or not in eventually consistent read model
If not exists; by using a redis-couchbase like keyvalue storage or cache; try to push the username as key field with some expiration.
If successful; then raise userRegisteredEvent.
If either username exists in read model or cache storage, inform visitor that username has taken.
Even you can use an sql database; insert username as a primary key of some lock table; and then a scheduled job can handle expirations.
Have you considered using a "working" cache as sort of an RSVP? It's hard to explain because it works in a bit of a cycle, but basically, when a new username is "claimed" (that is, the command was issued to create it), you place the username in the cache with a short expiration (long enough to account for another request getting through the queue and denormalized into the read model). If it's one service instance, then in memory would probably work, otherwise centralize it with Redis or something.
Then while the next user is filling out the form (assuming there's a front end), you asynchronously check the read model for availability of the username and alert the user if it's already taken. When the command is submitted, you check the cache (not the read model) in order to validate the request before accepting the command (before returning 202); if the name is in the cache, don't accept the command, if it's not then you add it to the cache; if adding it fails (duplicate key because some other process beat you to it), then assume the name is taken -- then respond to the client appropriately. Between the two things, I don't think there'll be much opportunity for a collision.
If there's no front end, then you can skip the async look up or at least have your API provide the endpoint to look it up. You really shouldn't be allowing the client to speak directly to the command model anyway, and placing an API in front of it would allow you to have the API to act as a mediator between the command and read hosts.
It seems to me that perhaps the aggregate is wrong here.
In general terms, if you need to guarantee that value Z belonging to Y is unique within set X, then use X as the aggregate. X, after all, is where the invariant really exists (only one Z can be in X).
In other words, your invariant is that a username may only appear once within the scope of all of your application's users (or could be a different scope, such as within an Organization, etc.) If you have an aggregate "ApplicationUsers" and send the "RegisterUser" command to that, then you should be able to have what you need in order to ensure that the command is valid prior to storing the "UserRegistered" event. (And, of course, you can then use that event to create the projections you need in order to do things such as authenticate the user without having to load the entire "ApplicationUsers" aggregate.

Resources