How to Secure CouchDB - security

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.

Related

How to verify the requester of a Node API

I have a Cloudflare Worker that presents a registration form, accepts input from the user that is posted back to the Worker which then sends that on to an Node HTTP API elsewhere (DigitalOcean if that matters) that inserts the data into a MongoDB (though it could be any database). I control the code in both the CF-Worker and the API.
I am looking for the best way to secure this. I am currently figuring to include a pre-shared secret key in the API call request headers and I have locked down what this particular API can do with database access control. Is there an additional way for me to confirm that only the CF Webworker can call the API?
If this is obvious to some I apologize. I have always been of the mind that unless you are REALY good at security it is best to consult those who are.
You can research OAuth2.0 standard. That is authorization standard for third party clients. Here is link: https://oauth.net/2/
This solution is the most professional.There are other less secure ways to do it, but easier to implement. Password and username, x-api-key, etc..
It sounds to me that you can also block all IPs and allow only requests from that specific domain name (CF Worker)

Couchdb apply filter server side

I'm developing a mobile app using PouchDB (client-side) and CouchDB (server-side).
I need to secure docs in order to allow users to read/write his own documents only.
I did a filter for this, something like:
function(doc, req) {
return doc.owner == req.userCtx.name || doc.sharedWith == req.userCtx.name;
}
and it works well, but only if the request from client includes the filter:
/somedatabase/_alldocs?filter=filter/secure
I need CouchDB to use the filter in every request, with or without client explicitation, for obvious security reasons. Is this even possible? Otherwise which is the correct approch to handle these security issues?
There is a similar question here but the answer is not applicable in my case since I need to share docs between users and replicate them between all databases is not a valid option.
So I don't know if you have looked at this wiki but it lists few options available. Some of them are outdated tho.
Per user database
Probably the most popular solution. As you said, you need to share documents with other users. This could be done by :
Copy document to other users when sharing. You could have a deamon that listen to _changes feed and update the author file in other users database.
Build a web service to access shared documents (very similar to proxy solution)
Smart Proxy
Build a smart proxy in front of your database and do some business logic to fetch the documents. This gives you more control on your data flow but it will surely be slower.
Note
The validate_doc_read server function could interest you but it has never been part of CouchDB's releases(due to the listed limitations).
Uhm, probably it isn't. The app that we are developing need to share documents with different users. any doc could be shared with a different group of users

NodeJS/express - security for public API endpoint

I'm developing my web-site project based on NodeJs/Express, and for some UI parts I'm using Jquery ajax request to fetch secondary data.
How can we handle some basic control on our Rest API end-points that are used for ajax calls by the browser?
I was thinking about some kind of token authorization , but it can be also used by other clients (scripts etc.) once it has been intercepted , so how can we protect our server from unwanted requests? What other controls should be used in this cases (recognize too many request from same client, clients black list,etc)?
There are three main topics Authentication, Authorization, Security. I will give links and only shortly answers. Subject is enough big to write few books.
Authentication - who is the one who is making request. There are many 'strategies' to authentication user. Please check most pupular module for this : http://passportjs.org/docs.
Of course you can inplement one or more of this strategies alone.
For stateless authentication jwt tokens are very convenient. If you want to code it yourself (Passport has this strategy) check this link (one of many in web) https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens.
How to prevent from token interception? Use always https and set token expiration time short.
Where to store your token client side? for detail look at this https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage/ In short don't store in web storage because of XSS attacks. Use cookies, when they are correctly configured they are safe (more in attached link), if not configured they are very exposed to threats.
Authorization : we know user, but he has access only to some resources. Please check https://github.com/OptimalBits/node_acl
There is gist with node_acl and passport : https://gist.github.com/danwit/e0a7c5ad57c9ce5659d2
In short passport authenticate user. We now who want what. We setup roles and resources and define roles and resources relation. Then we set for each user roles. Module will check for us user permission.
Security: please look for this subject in documentation of sails framework http://sailsjs.org/documentation/concepts/security they describes attacks and how framework prevent form them. I write about express:
DDOS: (part of your question "too many request from same client") "At the API layer, there isn't much that can be done in the way of prevention". This is subject most for servers admins. In short use load balancer. If it is one IP (not hundreds) then blacklist or deley response (for start look at this https://www.npmjs.com/package/delayed-request but I thing that solution must be more sophisticated).
CSRF: "type of attack which forces an end user to execute unwanted actions on a web application backend". Look at this module https://www.npmjs.com/package/csrf
XSS: "type of attack in which a malicious agent manages to inject client-side JavaScript into your website" don't trust any data from user. Always validate, filter, santize. Look at this https://www.npmjs.com/package/xss
In documentation of sails, there is more attack types but above are most popular.
Use express session + passport (http://passportjs.org/)
Basically you should have a login to the website and than only authenticated users can call the REST apis.
now... if you don't want a login, than you can't really protect the APIs as the website by design is open.
You didn't specify much info so it is hard to say more than that.
Also DoS attacks can't be protected by your code, and usually its not the responsibility of the app server (in your case node.js express) to provide such protection. If someone wants your website down by doing DoS attacks, than without other layers (see https://en.wikipedia.org/wiki/Denial-of-service_attack#Defense_techniques) which mostly mean it is up to a router/switch/so on... to implement.

How to ease CouchDB read/write restrictions on _users database

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. :)

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.

Resources