Protecting data on the client - meteor

I was wondering if and how people are preventing data access on the client? Are people concerned with being able to perform insert/update/remove from the JS console with Meteor Apps?
I found this article describing how to limit database access on the client but its pretty old and not sure if it is still relevant. They describe this as a way to prevent the client from updating the database:
// Relies on underscore.js. In your project directory:
// $ meteor add underscore
Meteor.startup(function() {
var collections = ['collection_name_1', 'collection_name_2'];
_.each(collections, function(collection) {
_.each(['insert', 'update', 'remove'], function(method) {
Meteor.default_server.method_handlers['/' + collection + '/' + method] = function() {};
});
});
});

The Meteor accounts system has been extended since 0.5.0. It provides a collection.allow method that allows you to define limitations to access a collection. Check the docs.
The insecure package on Meteor allows all clients to edit any collection in the database. You need to ensure to meteor remove insecure and this will default to deny all clients to write to database.
The parties example screencast talks about this in detail.

I asked a similar question recently (What logic must I cover in Collection.allow and Collection.deny to ensure it's secure?)
I find Meteor's allow and deny collections to be woefully insecure. You're right, anyone can just edit the data they have available. And it's up to you to write your Allow function to properly check exactly how a user might manipulate a document.
At some stage, I'm sure Meteor will have built in features like schema checking or whatever to may it easier to do this in the future. Right now, I've concluded the easiest and cleanest thing I've found is to just revoke all server side database permissions on the client side and just do all write operations with Meteor.calls and do my own validations that way

Related

Is meteor's package aldeed:autoform insecure?

In my way learning Meteor the past weeks, trying to build a simple crud with some validation I stumbled upon something.
Until today, I've been trying to keep my Collection Schema on server's side, and had some difficulties rendering Schemas server validation on the client, so I added aldeed:autoform.
When I started playing with autoform, after a few errors, I was surprised to realize that a Collection's Schema HAD to be defined on client side in order to work properly.
Doesn't that seems a bit dangerous? Should the schema of your Collections be published on the client?
It is maybe a stupid question, im not sure. I'll apologize in advance :D
You'll need to define the schema so that it is accessible by both the client and the server code. This is because, the form validation is done once at the client side (which should be always treated as insecure as it's made available in the browser console like below) and once on the server side. The server side validation is always considered secure. So even if you manage to manipulate the form from the browser by whatever means, if the validation does not fall in line with the schema, it gets filtered out on the server side so long as the schema is attached to the collection. I believe this way it's secure.
Meteor autoform page suggests you to remove insecure and add allow/deny rules.
Be sure to define proper insert security for untrusted code if you've
removed the insecure package. Call allow/deny or use
ongoworks:security.
Steps I follow to keep things secure (please be aware that there may be better ways, since I'm also fairly new to meteor universe)
Remove autopublish and insecure.
Define schema with allow/deny rules.
Use meteor server methods to insert / update.
Whether you use the schema attached to a collection or a schema to just validate a form and not really want it to be attached to a collection, make sure you call [check()][4] on the server code so that the once the form is submitted at the client end to the server, the server further explicitly checks if the data is still in accordance with the schema and nothing has been injected / tampered with by someone or something untrusted. If it is manipulated, the server side validation automatically filters out the extra additions on to the data passed to it.
This is what happens if someone adds extra data into which does not exist / conform to the schema definition:

Meteor: Publish/Subscribe Without Removing Auto-publish?

Hi I just get in touch with Meteor. First impression, cool...
I have question, is it possible to use publish/subscribe without removing autopublish?
I mean use both autopublish and publish/subscribe together. In certain part of app will be best using autopublish. In other part of app will be best using publish/subscribe
Thank you...
If you are using autopublish, it becomes a global service of your app so using manual publish/subscribe would be redundant.
However, there is a subtle feature of a publication, its name.
If you don't give a name to a publication, the contents of the publication is delivered to all connected clients. For example:
Meteor.publish(null, function() {
return Posts.find();
})
Now in order to get your Posts from the client, you don't have to subscribe. It will already be there.
No. Autopublish puts all the data from the server onto the client. Any publish/subscribe used in addition to autopublish will be redundant.

A meteor tutorial puzzle, is the client authorization safe?

I went through this tutorial and I'm trying to figure out how authorization works:
https://www.openshift.com/blogs/day-15-meteor-building-a-web-app-from-scratch-in-meteor
I see that client-side code is well written and that it handles privileges for logged in users through calls to
if(Meteor.userId())
but as far as I can tell nothing is handling client authorization in the server-side code in epollserver.js.
I tried to create a script that likes questions in a for loop but failed :) So I'm wondering if I'm missing something about the blog, something about the way metamagics work in meteor or if the tutorial actually results with unsafe code?
Meteor has a built in accounts functionality, so it has a login package called accounts-base that handles this for you.
The code is in the background and not in your main project files. You can view the package's contents here: https://github.com/meteor/meteor/tree/devel/packages/accounts-base.
Meteor is slightly different in the way security is handled. The tutorial you're using doesn't mention it much, perhaps this is why the question comes about.
Its slightly mentioned with the insecure package. In meteor you can't just update fields as you please in the database without corresponding .allow rules (docs: http://docs.meteor.com/#allow).
If you keep the insecure package in, installed by default, you can edit collections as you please. This is why the tutorial recommends removing it.
Allow rules and Publish
You can specify a rule that tells meteor that only certain users are allowed to alter the database.
Likewise when it comes to autopublish, you can control what database data is sent down from the server to the client.
Combined, these two are what make meteor secure in the same way as conventional web applications. You have a browser which can see html and js, but when it comes to what data it can see or what data it can update it is controlled in a secure fashion.
On client-side, you can use Meteor.userId() to manage display fo logged user or anonymous.
In fact you can think it's not secure, but in fact it's enough, if you think well your server-side code. Let's me explain :
In meteor Js, you manage collection through publish/subscribe and direct network call through Meteor.call. So you have to secure both, on server-side.
For the first one you have to remove insecure and autopublish.
Then use allow/deny on your collections to manage who can insert/update/remove data.
Then in your publish functions, that are only on server-side, you have to add :
if (!this.userId) return this.error(new Meteor.Error(403, 'unauthorized access'));
For the second one (Meteor.call) you just have to add in all required Meteor.methods (on server-side) :
if (!Meteor.userId()) throw new Meteor.Error(403, 'unauthorized access');
With those thing your application is "secure". Yes a user can hack your client code to try to display templates that should be available only for logged user, but in fact, this user will not be able to retreive any data, so yes it is secure !
Also don't forget to split your server and client code in different folder (server and client) or all the code will be downloaded by the client. And this is not secure !
Hope it helps you understand Meteor Js.
Actually, the tutorial does result with unsafe code since I managed to add a question through the JS console without being logged in, my initial hunch that the code lacks server-side checks was correct
I suspect three more if(Meteor.userId()) in epollserver.js would fix the issue, it's a basic authorization coding failure of not observing the mantra "protect from the server first, then from the client if necessary"

How can I sync the value of Meteor's userId to the client?

I'm not currently able to use all of Meteor's accounts functionality for compatibility reasons. My system is quite simple, though, I expose an "authenticate" method on the server that performs the necessary authentication work and then, if successful, sets the value of Meteor.userId() via this.setUserId. The only problem is that when I call this.setUserId on the server, it doesn't seem to propagate back to the client. Meter.userId() continues to return null on the client, but returns the correct value on the server. Since this.setUserId is a server-only function, I'm at a loss as to how I can set the correct user ID on the client after the "authenticate" method returns. Ideas?
You need to do more than just set the userId in order to authenticate a user. Check out these examples for how to do custom authentication:
https://github.com/tmeasday/meteor-accounts-anonymous (creates a user for each browser session)
https://github.com/mizzao/meteor-accounts-testing (creates users without passwords)
The second one is my example. I would strongly suggest building off the functionality provided by the base accounts package instead of rolling all your own operations.
EDIT: Based on the OP's response, one might be interested in doing a different kind of operation that is not about authenticating; see the following:
https://dweldon.silvrback.com/impersonating-a-user
Despite the fact that the Meteor documentation lists "this.setUserId()" as Server-only, it does currently work on the client too, so that's how I ended up solving this issue.

Getting values from the server

Let's say I don't want my client to have access to a collection, but I do want my client to be able to ask certain questions about objects within that collection. How would I achieve this?
As an example, let's say I want to know if there's currently a user logged in. When a user first logs in, I set that user's database id in Session and in a cookie. Currently, the application says a user is logged in if !Session.equals("user_id", null), which of course is very insecure because now I can open firebug and say Session.set("user_id", "foo") and now I'm logged in.
I don't want the client to have access to the Users collection at this point. The only client code that has access to this collection is enclosed in a self executing function in an effort to protect it (I'm not really sure if that's the right way to do security in Meteor, so feel free to recommend something along those lines as well). So instead I'd like to call some server side code and pass it the id that's set in session and have it tell me if that's a valid user or not.
Here's how I'd like to see it setup:
// client
function logged_in() {
return SomeServerMethodThatValidatesUserId(Session.get("user_id"));
}
Meteor.methods doesn't seem to fit the bill, since Meteor.call performs an asynchronous callback. The pub/sub model looks a little more promising, but from the documentation, I'm not quite sure how it works.
It seems to suggest that I should call this.set from within the publish handler in order to set some values on the client, but I can't figure out where those values become available.
Or maybe the pub/sub model isn't right for this either and there's another way that I'm missing. Any advice is appreciated!
It sounds like you're trying to restrict the client from accessing data until it's been authenticated. Here's one way to do that:
First, write a Meteor.publish function on the server that takes a user_id argument. Your function does whatever check you want in the privileged server environment and ultimately returns a Cursor. One simple example would be:
// define collection on both client and server
Users = new Meteor.Collection('users');
// server-side publish
Meteor.publish('my-user', function (user_id) {
if (someServerMethodThatValidatesUserId(user_id))
// publish a single user object to the client
return Users.find({_id: user_id});
});
Then on the client, subscribe to the my-user set once you have a user_id in hand:
// client-side
Meteor.subscribe('my-user', Session.get('user_id'));
Now, you'll have one document in Users on the client if and only if the user_id was valid, as determined by your privileged function someServerMethodThatValidatesUserId that runs on the server.
(this.set is available inside your publish function if you want to manually manage the specific documents that get sent to the client, instead of relying on a Mongo query. But I don't think anything like that is necessary here.)
This is an old question from the age before Meteor had authentication. The TL;DR answer is:
meteor remove autopublish
Then, manage your own collections, publications and subscriptions.

Resources