"Nullifier" une variable en ruby [dupliquer]
J'ai un cas d'utilisation où j'ai besoin de disposer de certaines données au moment même où je n'en ai plus besoin , pour des raisons de sécurité.
J'écris un serveur en Ruby qui traite les connexions et les mots de passe. J'utilise BCrypt pour stocker les mots de passe dans ma base de données. Mon serveur reçoit le mot de passe, en fait un hachage bcrypt, puis n'utilise plus le mot de passe d'origine.
Je connais une sorte de cyberattaque qui consiste à voler des données directement dans la RAM, et je crains qu'un attaquant puisse voler le mot de passe d'un utilisateur sous forme de chaîne brute pendant la période pendant laquelle le mot de passe est encore en mémoire. Je ne sais pas si la simple utilisation password_in_string_form = nil
suffirait.
Je veux annuler la variable qui contient le mot de passe de l'utilisateur au moment où j'en ai terminé. Par nullify, je veux dire quelque chose qui ressemble à l'utilisation de / dev / null pour remplir quelque chose avec des zéros. L'objectif final est la destruction irréversible des données .
Réponses
Je ne suis pas sûr que la simple utilisation
password_in_string_form = nil
suffirait.
Non, ce ne serait pas suffisant. L'objet peut être récupéré immédiatement ou non, et même s'il l'était, cela n'entraîne pas l'effacement du contenu de la mémoire.
Cependant, à moins qu'elles n'aient été gelées, les chaînes Ruby sont mutables . Ainsi, tant que vous ne figez pas la chaîne du mot de passe, vous pouvez remplacer son contenu par des zéros, ou des caractères aléatoires, ou quoi que ce soit avant de le lâcher. En particulier, cela devrait fonctionner, sous réserve de quelques réserves, abordées plus tard:
(0 ... password_in_string_form.length).each do |i|
password_in_string_form[i] = ' '
end
Mais il faut faire preuve de prudence, car cette approche, qui peut paraître plus idomatique, ne fonctionne pas :
# SURPRISE! This does not reliably remove the password from memory!
password_in_string_form.replace(' ' * password_in_string_form.length)
Plutôt que de mettre à jour le contenu de la chaîne cible sur place, replace()
libère le contenu vers l'allocateur interne de Ruby (qui ne le modifie pas) et choisit une stratégie pour le nouveau contenu en fonction des détails du remplacement.
La différence d'effet entre ces deux approches devrait cependant être un gros signal d'avertissement pour vous. Ruby est un langage de très haut niveau. Cela vous donne beaucoup d'effet de levier, mais au prix du contrôle des détails fins, comme si et combien de temps les données sont conservées en mémoire.
Et cela m'amène aux réserves. Voici les principaux:
Lorsque vous manipulez la chaîne de mot de passe, vous devez faire attention à ne pas en faire des copies ou à une partie de celle-ci, ou bien à capturer toutes les copies et à les effacer également. Cela demandera une certaine discipline et une attention aux détails, car il est très facile de faire de telles copies.
La corbeille de la chaîne de mot de passe elle-même peut ne pas être suffisante pour atteindre votre objectif. Vous devez également supprimer toutes les autres copies de mot de passe en mémoire, par exemple en amont de l'isolement de la chaîne de mot de passe. Si la vôtre est une application Web, par exemple, cela inclurait le contenu de la requête HTTP dans laquelle le mot de passe a été livré à votre application, et probablement plus de chaînes dérivées de celle-ci que la chaîne de mot de passe isolée. La même chose s'applique à d'autres types d'applications.
les mots de passe ne sont peut-être pas la seule chose que vous devez protéger. Si un adversaire est en mesure de voler des mots de passe dans la mémoire de la machine hôte, il est également en mesure de voler les données sensibles auxquelles les utilisateurs accèdent après la connexion.
Pour ces raisons et d'autres, si les exigences de sécurité de votre serveur imposent que les copies en mémoire des mots de passe utilisateur soient détruites dès qu'elles ne sont plus nécessaires, alors (pur) Ruby peut ne pas être un langage d'implémentation approprié.
D'un autre côté, si un adversaire obtient un accès suffisant pour récupérer les mots de passe de la mémoire / échange, alors la partie est probablement déjà terminée. Au minimum, ils auront accès à tout ce à quoi votre application peut accéder. Cela ne rend pas les mots de passe totalement inutiles, mais vous devez en tenir compte dans votre évaluation des efforts à consacrer à ce problème.
Ce n'est pas possible dans Ruby.
Vous devrez écrire du code spécifique à chaque implémentation (Opal, TruffleRuby, JRuby, Rubinius, MRuby, YARV, etc.) pour vous en assurer. En fonction de l'implémentation, il peut même ne pas être possible de faire à l' intérieur de la mémoire gérée de l'implémentation, sans avoir un morceau de mémoire séparé que vous gérez vous-même.
C'est-à-dire que vous aurez probablement besoin d'un petit morceau de code natif qui gère son propre petit morceau de mémoire native et l'injecte dans votre programme Ruby.