11

CouchDB has a mechanism in place to prevent unauthorized writes.

Can it also prevent unauthorized reads?

nornagon
  • 15,393
  • 18
  • 71
  • 85

1 Answers1

23

Yes, CouchDB can prevent unauthorized reads. Unfortunately, it is slightly less straightforward.

Imagine a secret auction application. You bid $20 and I bid $10; each bid in a couch document. Couch lets us read our own bid documents but no others. However, there is a map-reduce view showing the average. I load the view and see that the average is $15, so I conclude that your bid is $20 and I have broken the security policy. View output can leak some or all of a document's information. It is not feasible to enforce security at the document level. That is why read access is at the database level.

I know, it sucks. But that is the only correct, scalable answer.

This is part of the reason the Couch philosophy is to create many databases—even one (or more!) per user. Read permission to a database is set in the readers value of the database _security object. (Note, the field readers was renamed to members in CouchDB trunk because it also specifies who may write to the DB.)

The technique works like this:

  1. Create a database for each user. It will hold all documents the user may read. Add the user (or the user's role) to the _security object.
  2. In the master database, create a filter function which implements the read policy. (It could share code with validate_doc_update.)
  3. Replicate from the master database to the user's database with ?filter=my_filter_function.
  4. Allow the user to load (or replicate from) their database.

Of course, this is all for a pure Couch application, where users access Couch directly. If you have a middle layer (MVC controller, or just a reverse HTTP proxy), then you can enforce policy there, between the user and the couch. But be careful. For example, a _show function or a _rewrite rule might allow a user to load a view or document despite your policy.

Good luck!

JasonSmith
  • 72,674
  • 22
  • 123
  • 149
  • Thanks! Could you elaborate on how _show and _rewrite could bite me? Also, how do I avoid race conditions like "unfriend someone -> upload photo" and being 100% sure that the unfriended person can never see that photo? – nornagon Jan 19 '11 at 03:49
  • Well, suppose you have a reverse proxy that allows/denies access per document per user based on the URL. Later, you add a new feature using a _list function and all _list queries are allowed by the proxy. A user might figure out how to use the _list to see documents he shouldn't. Similarly, a _rewrite rule may provide a way to see documents without the normal `/db/doc_id` path. So you have to be *very* sure that your proxy has no holes. – JasonSmith Jan 19 '11 at 06:55
  • 2
    Your second question is more about **revoking** read access than **granting** read access. I propose you ask a fresh question ("How to revoke read access in the CouchDB security model"). I'll take a shot at an answer if I can! – JasonSmith Jan 19 '11 at 06:56
  • creating a database for each user would require the application to know the server admin credentials AFAIK. Isn't that a risk considering that the same credentials can be used to wipe out all the databases running on a cluster? – rahulmohan Feb 07 '17 at 22:16