web-dev-qa-db-fra.com

Comment protéger le champ de mot de passe dans Mongoose/MongoDB afin qu'il ne retourne pas dans une requête lorsque je remplis des collections?

Supposons que j'ai deux collections/schémas. L'un est le schéma des utilisateurs avec les champs nom d'utilisateur et mot de passe, puis j'ai un schéma de blogs qui contient une référence au schéma des utilisateurs dans le champ auteur. Si j'utilise Mongoose pour faire quelque chose comme

Blogs.findOne({...}).populate("user").exec()

Le document Blog et l'utilisateur seront également renseignés, mais comment puis-je empêcher Mongoose/MongoDB de renvoyer le champ mot de passe? Le champ mot de passe est haché mais il ne devrait pas être retourné.

Je sais que je peux omettre le champ mot de passe et renvoyer le reste des champs dans une requête simple, mais comment procéder avec peupler. En outre, y a-t-il une manière élégante de faire ceci?

De plus, dans certaines situations, le champ du mot de passe est nécessaire, par exemple lorsque l'utilisateur souhaite se connecter ou modifier le mot de passe.

60
Luis Elizondo
.populate('user' , '-password')

http://mongoosejs.com/docs/populate.html

JohnnyHK répond en utilisant les options de schéma est probablement le chemin à parcourir ici.

Notez également que query.exclude() n'existe que dans la branche 2.x.

49
aaronheckmann

Vous pouvez modifier le comportement par défaut au niveau de la définition de schéma à l'aide de l'attribut select du champ:

password: { type: String, select: false }

Ensuite, vous pouvez le récupérer au besoin dans les appels find et populate en sélectionnant le champ '+password'. Par exemple:

Users.findOne({_id: id}).select('+password').exec(...);
207
JohnnyHK

Modifier: 

Après avoir essayé les deux approches, j'ai constaté que l'approche d'exclusion ne fonctionnait toujours pas pour moi pour une raison quelconque en utilisant une stratégie de passeport local, je ne sais pas vraiment pourquoi.

Donc, voici ce que j'ai fini par utiliser:

Blogs.findOne({_id: id})
    .populate("user", "-password -someOtherField -AnotherField")
    .populate("comments.items.user")
    .exec(function(error, result) {
        if(error) handleError(error);
        callback(error, result);
    });

Il n'y a rien de mal à l'approche d'exclusion, elle n'a tout simplement pas fonctionné avec un passeport pour une raison quelconque, mes tests m'ont indiqué qu'en fait, le mot de passe était exclu/inclus lorsque je le voulais. Le seul problème avec l'approche toujours inclue est que je dois passer par tous les appels que je fais à la base de données et exclure le mot de passe, ce qui représente beaucoup de travail.


Après quelques bonnes réponses, j'ai découvert qu'il y avait deux façons de le faire, le "toujours inclure et exclure parfois" et le "toujours exclure et inclure parfois"?

Un exemple des deux:

L'inclusion toujours mais exclure parfois exemple:

Users.find().select("-password")

ou

Users.find().exclude("password")

L'exlucde toujours mais inclure parfois exemple:

Users.find().select("+password")

mais vous devez définir dans le schéma:

password: { type: String, select: false }
14
Luis Elizondo

User.find().select('-password') est la bonne réponse. Vous ne pouvez pas ajouter select: false sur le schéma car il ne fonctionnera pas si vous souhaitez vous connecter.

7
Ylli Gashi

En supposant que votre mot de passe soit "mot de passe", vous pouvez simplement faire:

.exclude('password')

Il y a un exemple plus complet ici

Cela se concentre sur les commentaires, mais c'est le même principe en jeu.

Cela revient à utiliser une projection dans la requête dans MongoDB et à transmettre {"password" : 0} dans le champ de projection. Voir ici

4
Adam Comerford

La solution est de ne jamais stocker les mots de passe en texte clair. Vous devriez utiliser un paquetage comme [bcrypt]1 ou [password-hash]2 .

Exemple d'utilisation pour hacher le mot de passe:

 var passwordHash = require('password-hash');

    var hashedPassword = passwordHash.generate('password123');

    console.log(hashedPassword); // sha1$3I7HRwy7$cbfdac6008f9cab4083784cbd1874f76618d2a97

Exemple d'utilisation pour vérifier le mot de passe:

var passwordHash = require('./lib/password-hash');

var hashedPassword = 'sha1$3I7HRwy7$cbfdac6008f9cab4083784cbd1874f76618d2a97';

console.log(passwordHash.verify('password123', hashedPassword)); // true
console.log(passwordHash.verify('Password0', hashedPassword)); // false
2
Cameron Hudson

Vous pouvez y parvenir en utilisant le schéma, par exemple:

const UserSchema = new Schema({/* */})

UserSchema.set('toJSON', {
    transform: function(doc, ret, opt) {
        delete ret['password']
        return ret
    }
})

const User = mongoose.model('User', UserSchema)
User.findOne() // This should return an object excluding the password field
2
Ikbel

J'utilise le champ Mot de passe masqué dans ma réponse JSON REST

UserSchema.methods.toJSON = function() {
 var obj = this.toObject();
 delete obj.password;
 return obj;
}

module.exports = mongoose.model('User', UserSchema);
1
Gere

Lorsque vous utilisez password: { type: String, select: false }, gardez à l’esprit que cela exclura également le mot de passe lorsque nous en aurons besoin pour l’authentification. Alors soyez prêt à gérer comme vous le souhaitez.

0
Anand Kapdi

Vous pouvez passer un objetDocumentToObjectOptionsàschema.toJSON ()ouschema.toObject ().

Voir la définition TypeScript à partir de @ types/mongoose

 /**
 * The return value of this method is used in calls to JSON.stringify(doc).
 * This method accepts the same options as Document#toObject. To apply the
 * options to every document of your schema by default, set your schemas
 * toJSON option to the same argument.
 */
toJSON(options?: DocumentToObjectOptions): any;

/**
 * Converts this document into a plain javascript object, ready for storage in MongoDB.
 * Buffers are converted to instances of mongodb.Binary for proper storage.
 */
toObject(options?: DocumentToObjectOptions): any;

DocumentToObjectOptions} _ a une option de transformation qui exécute une fonction personnalisée après la conversion du document en objet javascript. Ici, vous pouvez masquer ou modifier les propriétés pour répondre à vos besoins.

Donc, supposons que vous utilisiez schema.toObject () et que vous souhaitiez masquer le chemin d'accès au mot de passe de votre schéma d'utilisateur. Vous devez configurer une fonction de transformation générale qui sera exécutée après chaque appel à toObject ().

UserSchema.set('toObject', {
  transform: (doc, ret, opt) => {
   delete ret.password;
   return ret;
  }
});
0
xepe

C’est plutôt un corollaire à la question initiale, mais c’est la question à laquelle j’ai été confrontée pour tenter de résoudre mon problème ... 

À savoir, comment renvoyer l'utilisateur au client dans le rappel user.save () sans le champ mot de passe.

Cas d'utilisation: l'utilisateur de l'application met à jour les informations/paramètres de son profil depuis le client (mot de passe, informations de contact, whatevs). Vous souhaitez renvoyer les informations utilisateur mises à jour au client dans la réponse, une fois que celui-ci a été enregistré avec succès sur mongoDB.

User.findById(userId, function (err, user) {
    // err handling

    user.propToUpdate = updateValue;

    user.save(function(err) {
         // err handling

         /**
          * convert the user document to a JavaScript object with the 
          * mongoose Document's toObject() method,
          * then create a new object without the password property...
          * easiest way is lodash's _.omit function if you're using lodash 
          */

         var sanitizedUser = _.omit(user.toObject(), 'password');
         return res.status(201).send(sanitizedUser);
    });
});
0
Bennett Adams