On 29/03/2011 11:54 PM, Robert Newson wrote:
You can get read access control by separating each users documents
into a separate database.

That's true, although it complicates whole-system replication and deployment. It's probably worth looking at doing, though at the moment the encryption method works well enough. (And the volume of user-specific data is quite low)

I'm curious to know where you store the encryption keys such that no
user can access the key of another user. Whatever you did to solve
that would seem to be sufficient to prevent the access you were
concerned about in the first place. Presumably there's also a
different key per user?

Each application that uses the db uses a common API, defined by a PHP library. Encryption/descryption keys are stored within the application's configuration, in the same place as application username:password. As I said, the db isn't being used directly by users.

I suppose if you wanted to handle the encryption/decryption *inside* couchdb itself, you could use update and show functions with the key being passed as a parameter.
* As long as https is used, those keys won't be sniffable.
* To get the keys to the user's client, you could store them in encrypted form within the user document, with the password as key. (That way if the password changes, you only have to re-encrypt one document.)

-Patrick



B.

On 29 March 2011 00:41, Patrick Barnes<[email protected]>  wrote:
On 29/03/2011 2:38 AM, Nebu Pookins wrote:

If you have some secure data floating around in your db, encryption can
  still be a good idea. Parts of one of my databases are encrypted,
because
  users need to be able to see some documents in the db but not others.

I'm curious as how you've implemented encryption in your DB. Was it
pure JavaScript, or did you use native libraries? Elsewhere in this
thread, I've started a new "branch" where I've started outlining my
concerns with a pure JavaScript solution and wondered if cryptography
could be included as a core feature of CouchDB.

I'm using couchdb as a database, not to serve up pages directly to users. As
a consequence, a 'user' is a web application, and multiple applications have
differing levels of access to the database.

Each application is allowed to store it's own 'application data' documents
and I override two methods in my document class to allow transparent
decryption/encryption of those docs when read/written. (see below)

The reason I implemented encryption is that there's no per-doc read access
control in couchdb, so without encryption, I'm not able to prevent
applications from accessing another application's document. It's not as good
a solution as proper access control.

-Patrick


        /**
         * Given an object - load all the attributes from it into the
document - displacing existing attributes.
     * If the data field is encrypted, attempts to decrypt it.
         * @param stdClass $obj : An object with the desired attributes.
         **/
        public function loadFromObject(stdClass $obj) {
        parent::loadFromObject($obj);
        if ($this->doc_type != 'appdata') throw new
InvalidArgumentException("Wrong object type - Cgm_Appdata is for appdata
only");

        //Does the data section need to be decrypted?
        if (isset($this->encrypted) and $this->encrypted == true) {
            // Check that decryption info is stored
            $conf = Cgm_Document_Gateway::getAppConfig($this->source);
            if (!$conf->decrypt) throw new LogicException("Cannot load
document - no decryption is configured, and the document is encrypted.");

            // Decrypt and decode the data
            $decryptor = new Zend_Filter_Decrypt($conf->decrypt);

            $raw = base64_decode($this->data);
            $plain_json = trim($decryptor->filter($raw));
            $plain = json_decode($plain_json);

            if ($plain === NULL) throw new LogicException("Cannot load
document - decryption configuration is incorrect.");

            // Store the plain data within the object, in the same way as a
non-encrypted object.
            $this->data = $plain;
            unset($this->encrypted);
        }
        }

    /**
     * Export to an object.
     * If encryption is configured, attempts to encrypt the data field.
     * @return stdClass $obj
     */
    public function exportToObject() {
        $obj = parent::exportToObject();

        //Should the data section be encrypted?
        $conf = Cgm_Document_Gateway::getAppConfig($this->source);
        if ($conf->encrypt) {
            $encryptor = new Zend_Filter_Encrypt($conf->encrypt);
            $cryptdata = base64_encode( $encryptor->filter(
Zend_Json::encode($obj->data) ) );
            $obj->data = $cryptdata;
            $obj->encrypted = true;
        }
        //Was it encrypted before? - ensure that the flag is cleared
        elseif (isset($obj->encrypted)) {
            $obj->encrypted = false;
        }

        return $obj;
    }


Reply via email to