node package manager
Don’t reinvent the wheel. Reuse code within your team. Create a free org »

node-mongoose-alptekin-encryption

node-mongoose-alptekin-encryption

Bibliothek zur einfachen Verschlüsselung und Signierung von Mongoose Dokumenten. Die Bibliothek basiert auf MCrypt Twofish und Node crypto. Die Verschlüsselung und Signierung findet transparent gekapselt während des Speicherns und Ladens eines Dokumentes statt. Die gesamte BSON Struktur des Dokumentes wird dabei verschlüsselt, sodass auch Meta informationen unkenntlich gemacht werden.

Wie es funktioniert

Die Verschlüsselung wird mithilfe von Twofish-256-CBC mit einem kryptographisch zufälligen Initialisierungs-Vektor durchgeführt. Die Signierung erfolgt mithilfe von HMAC-SHA-512.

Bei der Verschlüsselung werden alle relevanten Felder aus dem Dokument entfernt, nach JSON konvertiert und anschließend verschlüsselt. Danach wird der Ciphertext im _cipher Feld dem Dokument hinzugefügt. Anschließend wird die _id und das _cipher Feld des Dokumentes mit HMAC-SHA-512 signiert.

Bei der Entschlüsselung wird zuerst auf Authentizität überprüft. Ist das Dokument authentisch wird das _cipher Feld entschlüsselt und die daraus resultierenden JSON Daten wieder zurück in das Dokument eingefügt.

Die genaue Implementierung kann im AlptekinTwofishHandler nachgelesen werden, der Code ist detailiert kommentiert und einfach verständlich.

Während dem Speichern-Vorgang wird das Dokument automatisch verschlüsselt und signiert. Gleiches gilt für den Lade-Vorgang, das Dokument wird vollautomatisch authentifiziert und entschlüsselt.

Installation

npm install node-mongoose-alptekin-encryption

Benutzung

Für jedes Schema sollte ein eigener Verschlüsselungskey generiert und an einem sicheren Ort auf dem Server abgelegt werden. Dieser ist der Anwendung über eine globale Variable zugänglich zu machen. Der Schlüssel muss eine Länge von 32-byte besitzen und sollte base64 codiert sein.

Basics

Standartmäßig werden alle Felder ausgenommen von _id, __v, und Feldern mit Indizes verschlüsselt. Die einbindung erfolgt in der Schema Definition wie folgt:

var mongoose = require('mongoose');
var encryptionPlugin = require('node-mongoose-alptekin-encryption').alptekinTwofishPlugin;
var bluebird = require('bluebird');
 
var schema = new mongoose.Schema({
    name: String,
    username: String,
    email: String,
    age: Number
    // whatever else
});
 
// Hier wird die erforderliche Konfiguration vorgenommen
// alle zusätzlich von der Bibliothek benötigten Felder sowie Methoden 
// werden automatisch hinzugefügt
schema.plugin(encryptionPlugin, {
  // Der zu benutzende Verschlüsselungskey
  encryptionKey: BASE64_32BYTE_KEY,
  // zusätzlich zu authentifizierende Felder
  authenticated: ['username', 'email'],
  // von der Verschlüsselung auszunehmende Felder
  excluded: ['username', 'email']
});
 
var User = mongoose.model('User', schema, 'user');
bluebird.promisifyAll(User);
bluebird.promisifyAll(User.prototype);
 
exports.User = User;

Die Konfiguration ist hiermit abgeschlossen. Dokumente können nun wie gewohnt gefunden, erstellt oder geladen werden. Durch Mongoose bedingte Funktionalität kann die normale update Funktionalität nicht mehr benutzt werden. Ein Dokument sollte bei einem Update zuerst geladen, dann manuell geupdated und anschließend normal gespeichert werden.

Sicherheitshinweis

Sollten Felder von der Verschlüsselung optional ausgenommen werden sollten diese auch immer zusätzlich zur Signierung hinzugefügt werden. Damit wird sichergestellt, dass sie nicht verändert werden.

Migration alter Daten

Wird das Plugin in einer leeren Collection benutzt, kann es sofort eingesetzt werden. Sind bereits Daten vorhanden muss eine Migration durchgeführt werden, da beim laden jedes Dokumentes eine Signatur erwartet wird.

Die Migration muss einmalig in einem Nightrun wie folgt ausgeführt werden:

// ersetze die normale Plugin definition wie folgt
schema.plugin(encryptionPlugin.migrate, {
  encryptionKey: BASE64_32BYE_KEY,
  // Alle später zusätzlich zu signierende Felder
  authenticated: ['username', 'email'],
  // Alle später von der verschlüsselung auszunehmende Felder
  excluded: ['username', 'email']
});
 
var User = mongoose.model('User', schema, 'user');
bluebird.promisifyAll(User);
bluebird.promisifyAll(User.prototype);
 
User.migrate()
  .then(function(success) {
    console.log(success);
  })
  .catch(function(error) {
    console.log(error);
  });

Nach einem Server restart sollte wieder die normale Plugin Konfiguration ins Schema eingefügt werden. Danach ist es sofort einsatzbereit und kann wie beschrieben benutzt werden.

Zusätzliche Sicherheitshinweise

  • Always store your keys and secrets outside of version control and separate from your database. An environment variable on your application server works well for this.
  • Additionally, store your encryption key offline somewhere safe. If you lose it, there is no way to retrieve your encrypted data.
  • Encrypting passwords is no substitute for appropriately hashing them. bcrypt is one great option. Here's one nice implementation. Once you've already hashed the password, you may as well encrypt it too. Defense in depth, as they say. Just add the mongoose-encryption plugin to the schema after any hashing middleware.
  • If an attacker gains access to your application server, they likely have access to both the database and the key. At that point, neither encryption nor authentication do you any good.

Acknowledgements

Es wurde sich an Joe Goldbeck's mongoose-encryption (https://github.com/joegoldbeck/mongoose-encryption) und Markus Engel's node-mongoose-hybrid-encryption (https://bitbucket.org/lmnflux/node-mongoose-hybrid-encryption/src) orientiert. Vielen Dank.

License

The MIT License (MIT)

Copyright (c) 2016 Melek Sahli Alptekin

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.