Olivier Scherrer

Olivier is a Front End Developer at Lab49, London, a strategy, design and technology consulting firm that creates advanced solutions for the world’s leading investment banks, asset managers and exchanges. He has a strong experience in developing real-time HTML5 applications.
He's the author of Emily and Olives, two JavaScript frameworks that allow to easily create powerful web applications on top of node.js, with high UI performance and low memory footprint.
Olivier is a Front End Developer at Lab49, London, a strategy, design and technology consulting firm that creates advanced solutions for the world’s leading investment banks, asset managers and exchanges. He has a strong experience in developing real-time HTML5 applications.
He's the author of Emily and Olives, two JavaScript frameworks that allow to easily create powerful web applications on top of node.js, with high UI performance and low memory footprint.View Olivier Scherrer on LinkedIn
  • ask me anything
  • GitHub podefr
  • Emily
  • Olives
  • rss
  • archive
  • Securing CouchDB in 3 steps

    Freshly installed, CouchDB offers little to no security. There’s even a name for that temporary state: its called the “Admin Party”, as every user is considered to be an admin.

    While it might seem dangerous, it’s actually a nice thing as it lets you fine tune the level of security you want to obtain.

    Say you’re in learning mode and you just want to figure out what CouchDB is and how it works. You’re creating databases and documents and fetching them through design documents. At this time there’s no need to secure anything, and anyway, CouchDB is bound to your local address so you’re the only one who can mess around with it.

    But start using it in production, with an application that manipulates sensible information, and you’ll have to go deeper into securing it.

    And that’s what i’m going to describe, in 3 steps.

    1. Identifying the user who issues the request
    2. Limiting a user’s read/write access to a database
    3. Limiting a user’s write access to his own documents

    1. Identifying the user who issues the request

    CouchDB stores its users in the _users database. A user document looks like this:

    {
        "_id": "org.couchdb.user:couchdb",
        "_rev": "1-8995e8ff247dae75048ab2dc800136d7",
        "name": "couchuser",
        "password": null,
        "roles": [
        ],
        "type": "user"
    }
    

    The _id is the user’s name prefixed with “org.couchdb.user”. _rev is the document’s revision. name is the name of the user, the one that the user will remember, along with his password. Roles is a feature that we’ll develop when speaking about _security documents. It allows to create some sort of groups for the users. Finally, type can only be user.

    While roles and type should be defined by the application during the account creation phase, name and password are chosen by the user. They are his credentials.

    More information on the authentication database in the official wiki

    So, how does one authenticate himself?

    Basic authentication

    This authentication mode is using the name:password@url style. For a couch user couchuser whose password is couchpass, the request url would be:

    http://couchuser:couchpass@localhost:5984/db/document
    

    Querying CouchDB with the user’s credentials will create a “user context” object that will be passed around to control functions, such as the validation functions we are going to talk about.

    Cookie authentication

    The second way of authenticating a user is by issuing a POST request on _session. The request must embed the credentials:

    curl -vX POST http://localhost:5984/_session -H 'application/x-www-form-urlencoded' \
    -d 'name=couchuser&password=couchpass'
    

    The response’s header will have a Set-Cookie field that can now be re-used to authenticate the user for 10 minutes, depending on your configure files.

    HTTP/1.1 200 OK
    < Set-Cookie: \
    AuthSession=Y291Y2hkYjo1MDQ2NUI3MjrL7w8A3NhUpW6XkVvVVJ25epeGsw; \
    Version=1; Path=/; HttpOnly
    

    You’re going to need to be able to extract the AuthSession from the header before passing it to further requests. Here’s an example of a request embedding AuthSession:

      curl [your request here] --cookie \
      AuthSession=Y291Y2hkYjo1MDQ2NUI3MjrL7w8A3NhUpW6XkVvVVJ25epeGsw
    

    More on authentication is available here.

    Now that the user is authenticated, we can control which databases he has access to.

    2. Limiting a user’s read/write access to a database

    Database-wise, there are two types of users, admins and readers.

    Readers can create, read and write document except for design documents. Database admins can also modify design documents and _security documents. They can do some other stuff but it’s not the purpose of this article.

    The _security document will simply specify what type of database user a CouchDB user is:

    // This example comes from the CouchDB guide
    {
        "admins" : {
            "names" : ["joe", "phil"],
            "roles" : ["boss"]
        },
        "readers" : {
            "names" : ["dave"],
            "roles" : ["producer", "consumer"]
       }
    

    }

    Notice the “roles” fields. Instead of adding every user in the names array of the _security document, you could instead specify which roles are admins or readers, and assign the adequate role to the user.

    As soon as a _security document is added to a database, any user not listed in is not granted any access. [need to double check on that]

    Authorization documents in the official wiki are explained here.

    We can now prevent users from wandering around in our application. But if a user’s granted access to a database, how can we secure write access to documents that he doesn’t own?

    3. Limiting a user’s write access to his own documents

    Design documents can have a validation function that is called everytime a document is altered. Here’s an example of a function that checks if the user who tries to modify a document is its owner.

    "validate_doc_update": "function (newDoc, oldDoc, userCtx) {
         if (newDoc.author != userCtx.name) { 
             throw({ 
                 forbidden: 'Only' + userCtx.name + ' may edit this document'
             });
         }
      }"
    

    Throw defines the error that is returned to the application. Other helper functions are available too:

    • required(field) : check if a field is set in a submitted document
    • unchanged(field) : prevent changes in a field
    • user_is(role) : check if user has given role

    UserCtx has other properties:

    • roles : the roles that are assigned to the user
    • db : the name of the database

    And a last argument is passed to the validation function, the database’s security document.

    More on validation functions.

    To go further, we could imagine adding a proxy, between CouchDB and the application, that would filter out dangerous requests. Querying the database through https should also be considered.

    In a future article, I will explain how to secure CouchDB when used by an OlivesJS/EmilyJS application.

    • September 5, 2012 (12:56 am)
    • 3 notes
    • #couchdb
    • #security
    • #nosql
    • #database
    1. mickey-84 likes this
    2. podefr posted this
© 2012–2013 Olivier Scherrer