How to ease CouchDB read/write restrictions on _users database - security

In my couchapp two databases are being used
1 Is for application data
2 Is "_users" database.
In my application In one form I'm trying to implement autocomplete where data source is a "view" created in "_users" database.
Now when I login with normal user id other than admin. While trying to access the view inside "_users" database I'm getting the error 403 which is :
{"error":"forbidden","reason":"Only admins can access design document actions for system databases."}
Is it possible for me to allow and limit the access for non admin users to that view only ? So I can get the list of users from _users database into my application.

I've never been able to do many tasks that require much custom with CouchDB by itself. I've always needed a script somewhere else that gives me the info that I need.
What works for me is this setup:
A gatekeeper Sinatra app that has admin access to my CouchDB
Using CouchDB's config to proxy to my Sinatra app. httpd_global_handlers _my_service {couch_httpd_proxy, handle_proxy_req, <<"http://127.0.0.1:9999">>}
The reason for the proxy is because any request that comes through to your gatekeeper will have the AuthSession token set. Inside your gatekeeper, you can GET localhost:5984/_session passing the AuthSession cookie along, it will tell you who is making the request, allowing you to look them up and see if they have access, or just give everyone access to whatever you like. Another reason for the proxy is to avoid any CORS nonsense since you're making the request to yourserver:5984/_my_service.
Update
A purely client-side/javascript solution means that it will be fundamentally insecure at some point, since well, everything is on the client-side. But perhaps your application, doesn't need to be that secure. That's up to you.
One workaround could be to make your application authenticate as a predefined admin, and then create more admin users that way. You could authenticate once when your application boots or on an as needed basis.
The "problem" is that CouchDB sees the _users database as fundamentally special, and doesn't give you the opportunity to change the credential requirements like other databases. Normally you would be able to use the _security document to give role based or user based access. But that's not possible with _users.
An alternative implementation might be to keep track of your own users and forgo the _users database altogether. In that case you could set your own cookies and have your own login and logout methods that don't depend on CouchDB's authentication scheme. You could query your own _view/users because it would be in your main database. Things wouldn't be locked down tight but they would work fine as long as no one was interested in hacking your system. :)

Related

Access Control in a Web Application

I'm currently reading a lot about access control possibilites/mechanisms that can be used to protect resources in an application or web application. There's ACL, RBAC, ABAC and many other concepts out there.
Assuming I have developed a simple webservice that returns knowledgebase articles on a route like '/api/article'. The 'controller' connects to the database and fetches all articles and returns them as XML or JSON.
Now I would like to have control over which article in the database is accessible for which user or group. So for instance if user 'peter' accesses the route '/api/article' with his credentials, the webservice shall return only articles that are visible for 'peter'.
I would want to use ACL to control what each user/group can read/write/delete. But what I don't quite understand:
Where does one enforce the access control? Do I just fetch all records in the controller if a user accesses the route '/api/articles' and check each single record against an access control list (that doesn't sound very good performance wise)? Or is there a way that the 'SELECT' statement to the database only return the records that can actually be seen by that specific user?
I really tried hard to find more information on that topic, and there is a lot about different access control mechanisms, but not about where and how the actual enforcement happens...and it even get's more complex if it comes to other actions like modification, deletion and so on...
This is really a matter of implementation and everyone does it its own way. It also depends on the nature of the data, particularly on the size of your authorization (do your have 5 roles and users are attached to them or does each user have a specific set of articles he can access, different for each user - for instance)
If you do not want to make the processing on the controller, you could store the authorization information in your database, in a table which links a user to a set of KB articles, or a role (which would then be reflected in the article). In that case your SELECT query would just pass the authenticated user ID. This requires that the maintenance of the relationship is done of the database, which may not be obvious.
Alternatively you can store the ACL on the controller and build a query from there - for specific articles or groups of articles.
Getting all the articles and checking them on the controller is not a good idea (as you mention), DBs have been designed also to avoid such issues.

CouchDB Security in a Lightweight Stack?

I'm working on a hobbyist project in order to become more familiar with CouchDB. This is my first time working with CouchDB. For this project, my goal is to investigate whether or not it's possible to build a web application with nothing but HTML, CSS, JavaScript, CouchDB, and nginx (i.e., I'm not hosting any of my code in Couch, just data).
It could be that this is highly impractical, but I'd first like to explore all the options in this stack.
At the moment, my biggest questions are about security. Let's say that I have a few databases in CouchDB, each corresponding to a hosted site. For this example, we'll focus on a single database-- i.e., a single site. Some of the content from this site should be available to everyone, even anonymous users; and other stuff should only be available to users with a certain role. What are my options, and how secure are each of them?
I've come up with a few ideas so far, and this is the one I was planning to work on over the weekend:
Add users and roles to /{site_db}/_security.
According to the Couch documentation, doing so will require any request for data in {site_db} to be from an authenticated user.
Add a user called anon, which will only have one role, which is anon.
When the user first visits the site, my JS model will check the status of the current session (GET /_session).
If no session exists, the JS model will authenticate using the anon account.
Define views in my design document.
Any views that should only be available to non-anonymous users should check the roles on the userCtx object.
Validation of any newly-created documents should check userCtx to see if the user's role is on the whitelist.
This seems like it should work, although I can't help thinking it's overly complex, and that there must be a better way. Also, I'm not sure how to prevent the anon user from updating his own user document to add more roles.
If you don't like CouchDB security model, you can implement yours easily in your reverse proxy instead.
Here is an example with Apache but it seems to be very similar in nginx.

SPA security using Backbone.js, Require.js and Laravel

I'm currently searching the best way for developing my next webapplication. I'm thinking about using Backbone.js and build a single page application. But I really can't imagine how to secure my app since nearly everything is done on client side. Of course I just could prevent the users from accessing my RESTful Api so they would not have access to my data. But all the view/model/collection/template js files are still accessible.
Or is there a known way to serve the js files with php (laravel), which would allow me to only serve the files I need for the respective user.
I just couldn't find a solution by searching the Web. But I just don't think that I am the lonely person who needs a clean and secure authentication method including different user rights.
Thank you in advance!
Your backend application will fetch data from a backend (= API), and probably send back some changes.
This code can't have "security holes / leaks" as long as your backend is secured.
If you are afraid of people stealing your code, you can always minify the JS (check grunt.js and almond.js for this)
To secure your backend you can make use of Laravel's auth class, and the auth filter as mentioned before.
Besides normal auth, you could implement roles, that you can assign to specific users, giving them more or less access to certain resources in your backend.
Here's the method I would try :
Separate the application in two parts.
One part - login via regular Laravel Auth on a separate page, and then when the user is logged in serve the single page app in a different view.
Wouldn't this work?
Web Services are no different than any other web application you build. At the end of the day you are exposing functionality to the client (which is also the attacker). It doesn't matter what the client is implemented in, if you expose dangerous functionality you will be hacked.
Have a session state, keep track of the user id and make sure that the user is only accessing resources they have been allowed to access.
I do not think that what JS/template files are exposed really matters. Essentially, you should only be allowing data interaction to authenticated users. Think of this as two separate applications.
The front-end application logs in, and a cookie is stored (or some other persistence is used).
The back-end application then uses the persistent authentication to validate every single user request for data, and every user action.
This way you don't have to worry about the security, the client can only fetch the data that the server allows it to, and, likewise, it can only interact with the data insofar as the server allows it. You shouldn't be relying on the client side for security anyway, even logged in, otherwise some malicious user could, conceivably, save all your frontend code and use it against you without authentication.

CouchDB - Figuring out database security

CouchDB offers validation prior to allowing an object/row to be inserted into the database. This make sure that if you have a public facing couch application, you're database won't be filled with junk by just anyone.
User <-> CouchDB
However, I'm tring to figure out what that looks like comming from the standard application design process where you have a trusted middle layer that does much of the auth work. For example, most apps place Ruby or PHP between the database and user agent which allows the application to figure out information about the user agent before allowing something like a post to be saved to the database.
User -> Ruby -> MySQL
User <- Ruby <- MySQL
How do you trust the user to do administrative tasks when the user can't be trusted?
For example, how would you do something like "email verification" prior to inserting a user row using just couchDB? You can't let the user agent insert the row - because they would fill the system with spam accounts. On the other hand, there is no middle layer either that can insert the row after they click the link in the email.
How about this, I would assume that you would allow anyone to enter their email by creating a new record in a public table like email_verify. This is something that a public user agent could do as the table would not do anything in the application - it would just be a holding tank.
Then node.js could track the _changes feed and send an activation email while creating a new entry in a private table (like email_confirm) (node.js would serve as a trusted middle layer). If the user clicks that link and comes back then... [unknown] ... and node.js could finally create a record in the private user table (user).
At this point we could then rely on couchdb validation for the rest of the application since we got a confirmed user account created.
As more background lets imagine a discussion built on couchdb that anyone can register for. We don't want to allow just anyone to directly submit content without some kind of verification - yet the user agents all directly run the system. (Tables would be Thread, Comment, & User). How would this work?
I would think about adding roles to existing users in this issue.
Using couchdb's validation and changing _design/_auth can be a good idea to add email, email_verified and randomly generated email_verification_code in _users database when the user firsts registers.
To send mail, get confirmation, resend confirmation you can use external processes. (for an example usage of external process you can check couchdb-lucene).
And at last you can again do a quick check in _design/_auth in user update process if verification code matches and add verified_user role for that user.
This way all your requests would pass over couchdb, you would use external process only when you need to send mail and get confirmation.
Edit : Forgot to add (since it was pretty obvious), I would add verified_user role to database readers.
Couldn't you just make use of CouchDb's Validation ?
Users could be flagged. Upon registration, a User is added to the Users database. He gets his mail and then is flagged "valid:true" or something like this upon answering to that mail or clicking a link.
With validation users could not only be "logged in/out" but also access authorization can be implemented with more granular access rights. E.g.: Only mark threads solved if one is the author, admin, whatever...
Or does this seem impracticable?
After talking with some people on #couchdb IRC, it seems that they can't figure out out a way to do something administrative (like activation users that click on a email link) with out using a "backend" process like a node.js server which keeps track of the _changes feed.
I was hoping for a pure couchdb app - but it seems like couchdb still has a little ways to go.
Still, the good news is that you can hand off 80% of your applications logic/processing to your users. The other 20% will be 1) a node.js instance for things like sending emails or checking recaptcha and 2) record validation functions running in your couchdb, and 3) map/reduce (query) functions. These three things cannot be offloaded to something "untrusted" like a user-agent.

How to Secure CouchDB

CouchDB access as a rest service seems insecure. Anyone can hit the database and delete/add documents once it is exposed.
What strategies are there to secure the CouchDB?
A lot has changed since 2009, so I'm going to throw an answer in here. This answer is drawn from this page on the wiki.
CouchDB has a _users database that serves the purpose of defining users. Here's the gist straight from the wiki:
An anonymous user can only create a new document.
An authenticated user can only update their own document.
A server or database admin can access and update all documents.
Only server or database admins can create design documents and access views and _all_docs and _changes.
Then, for any given database you can define permissions by name or by role. The way authentication is implemented is through a _session Database. Sending a valid username and password to the _session DB returns an authentication cookie. This is one of several option for CouchDB Authentication. There're a few more options:
This option is a little old 1.0 was a few months back, we're on 1.2 as of today. But it's still very well outlined.
And this one from "The Definitive Guide"
Also, depending on which hosting service you might be using, you'll have the option to restrict access to couch over SSL.
Between Node, Couch, and a variety of other technologies that effectively scale horizontally (adding more servers) there's an interesting kind of pressure or incentive being put on developers to make applications that scale well in that manner. But that's a separate issue all together.
The only thing which really works currently security wise is something like this in your CouchDB configuration.
[couch_httpd_auth]
require_valid_user=true
[admins]
admin = sekrit
This puts basic HTTP auth on all of CouchDB. Even this is not well supportet in client libraries. For python e.g. you need a patched library.
The second approach is to put a proxy in front of CouchDB and let the proxy do the authentication and authorization work. Due to CouchDB's RESTful design this is quite easy.
All other approaches must be considered up to now highly experimental.
This may be a little different from your original question. If your couchdb is only a back-end store for a full server app, you can make a special account for the server app to use and require those credentials for access to couchdb.
On the other hand, a pure couch app that people hit directly through a javascript client needs a lot of care to be secure.
Using rewrites is not optional. You need a vhosts config that forces requests to your domain through your rewrites.
Rewrite routes */_all_docs and /*/_design/* to a 404 page. Otherwise users can list every document or get your whole app.
Rewrite generic object access, ie /dbname/:id to a show that can deny access if the user is not allowed to see the document. Unfortunately there is no equivalent workaround for doc-based access control of attachments.
We used haproxy to filter GET requests on _users. There is no legit reason for someone from outside to get a user record or list all your users. We want users to be able to register so we need write access. Currently couch cannot block read access to a db and simultaneously allow writes. It's a bug. Filtering with something like haproxy is our best workaround for now.
Use your own database to keep contact information that is in addition to what is provided by _users. This allows more control over access.
validate_doc_update should carefully reject any writes that should not be allowed.
In every case you need to imagine what someone who understood the system could do to subvert it and lock down those avenues of attack.
CouchDB does cookies, SSL, oauth, and multi-users just fine:
Here's some actual code in python:
from couchdb import Server
s = Server("https://user:password#example.com:6984")
Request the cookie: url encoded above and below, of course
You have to put the credentials twice to get started with the first cookie
Both in the Server() constructor as well as the _session POST body
code, message, obj = s.resource.post('_session',headers={'Content-Type' : 'application/x-www-form-urlencoded'}, body="name=user&password=password")
assert(code == 200)
Now you have received a cookie, extract it
cookie = message["Set-Cookie"].split(";", 1)[0].strip()
Now, exit python and restart
Next, Request a server object, but without the username and password this time
s = Server("https://example.com:6984")
s.resource.headers["Cookie"] = cookie
Yay, no password, try to access the database:
db = s["database"]
Optionally set the "persistent" cookie option on the server side to make the cookie last longer.
Have you read CouchDB documentation http://couchdb.apache.org/docs/overview.html? It has a "Security and Validation" section that addresses some of your concerns.

Resources