Question:
Serait-il une bonne pratique de programmation sécurisée d'écraser une variable «sensible» avant de la supprimer?
Jonathan
2014-12-04 22:18:15 UTC
view on stackexchange narkive permalink

Est-ce une bonne pratique de programmation sécurisée d'écraser les données sensibles stockées dans une variable avant qu'elle ne soit supprimée (ou hors de portée)? Je pense que cela empêcherait un pirate informatique de lire des données latentes dans la RAM en raison de la rémanence des données. Y aurait-il une sécurité supplémentaire en l'écrasant plusieurs fois? Voici un petit exemple de ce dont je parle, en C ++ (avec commentaires inclus).

  void doSecret () {// Le secret que vous voulez protéger (probablement mieux ne pas l'avoir codé en dur comme ceci) int mySecret = 12345; // Faites ce que vous faites avec le nombre ... // ** Effacez la mémoire de mySecret en écrivant dessus ** mySecret = 111111; mySecret = 0; // Peut-être répéter plusieurs fois dans une boucle}  

Une idée est que si cela ajoute réellement de la sécurité, ce serait bien si le compilateur ajoutait automatiquement les instructions pour le faire (peut-être en par défaut, ou peut-être en demandant au compilateur de le faire lors de la suppression des variables).


Cette question a été présentée comme une Question de sécurité de l'information de la semaine .
Lisez le article de blog du 12 décembre 2014 pour plus de détails ou envoyez votre propre Question de la semaine .

Voir aussi: [la vue au niveau du système d'exploitation] (http://security.stackexchange.com/questions/74288/is-data-remanence-a-concern-in-ram)
Notez que cela peut être [délicat] (http://stackoverflow.com/questions/3785366/how-to-ensure-that-compiler-optimizations-dont-introduce-a-security-risk) en fonction de la [langue] ( http://stackoverflow.com/questions/3785582/how-to-write-a-password-safe-class). (Voir les deux questions liées et surtout leurs réponses)
Notez également que les chaînes en java sont immuables, donc l'écrasement (attribution d'une nouvelle valeur à la variable de référence) n'aura aucun effet.
Non seulement c'est une bonne idée, mais d'autres étapes que vous voudrez peut-être prendre sont de `mlock` la mémoire (pour vous assurer qu'elle n'est pas écrite pour échanger),` mprotect` la page afin qu'elle soit en lecture seule une fois que les données secrètes ont été initialisé (aussi éventuellement pour marquer la page comme non accessible * du tout * sauf dans les petites fenêtres dans lesquelles vous comptez y accéder), pour avoir une valeur "canari" écrite en mémoire immédiatement après le secret pour détecter lors de la désallocation si elle été écrasé par un débordement, et d'allouer des pages de garde supplémentaires non accessibles avant et après le secret à SEGV en cas de débordement et de sous-dépassement.
Voir [`sodium_malloc`] de libsodium (https://github.com/jedisct1/libsodium/blob/master/src/libsodium/sodium/utils.c#L392) comme implémentation de cela.
@rkosegi c'est pourquoi il faut utiliser byte [], pas string, pour les clés.
Le compilateur C / C ++ est en fait gratuit pour optimiser vos écrasements sauf si vous avez déclaré votre variable comme `volatile`, car ils ne changent pas le résultat de l'exécution du code (la valeur n'est utilisée nulle part).
La mise à zéro est requise par la [FIPS 140-2] du NIST (http://csrc.nist.gov/groups/STM/cmvp/standards.html), même aux validations de niveau 1. Les attaquants utilisent la mémoire, et ils n'ont pas besoin d'être locaux. Par exemple, nous savons que [la NSA enregistrera le rapport d'erreurs Windows dans son système XKeyscore pour aider à obtenir un accès non autorisé] (http://en.wikipedia.org/wiki/Tailored_Access_Operations).
Alors que la plupart des réponses mentionnent l'avantage d'écraser les données (si possible), je ne vois pas l'intérêt d'écraser "quelques fois en boucle" comme suggéré dans la question, mais pas abordé par le lot actuel de réponses AFAICS. À moins que ces données ne soient écrites sur un support magnétique et que l'attaquant ait un accès de bas niveau au système, j'aurais pensé que l'écrasement une fois devrait être suffisant? Ou plusieurs écritures sont-elles toujours bénéfiques?
Dix réponses:
goodguys_activate
2014-12-04 22:26:55 UTC
view on stackexchange narkive permalink

Oui, c'est une bonne idée d'écraser puis de supprimer / libérer la valeur. Ne supposez pas que tout ce que vous avez à faire est "d'écraser les données" ou de les laisser tomber hors de portée du GC, car chaque langue interagit différemment avec le matériel.

Lors de la sécurisation d'une variable, vous devrez peut-être penser à:

  • chiffrement (en cas de vidage de mémoire ou de mise en cache de page)
  • épinglage en mémoire
  • possibilité de marquer comme lecture seule (pour empêcher toute modification ultérieure)
  • construction sûre en ne permettant PAS de passer une chaîne constante dans
  • l'optimisation des compilateurs (voir note dans l'article lié concernant la macro ZeroMemory)

La mise en œuvre réelle de "l'effacement" dépend de la langue et de la plate-forme. Recherchez le langage que vous utilisez et voyez s'il est possible de coder en toute sécurité.

Pourquoi est-ce une bonne idée? Crashdumps et tout ce qui contient le tas peut contenir vos données sensibles. Pensez à utiliser les éléments suivants lorsque vous sécurisez vos données en mémoire

Veuillez vous référer à StackOverflow pour les guides d'implémentation par langue.

Vous devez être conscient que même lorsque vous utilisez fournisseur (MSFT dans ce cas), il est toujours possible de vider le contenu de SecureString, et peut avoir des directives d'utilisation spécifiques pour les scénarios de haute sécurité.

La question portait sur l'écrasement d'abord, puis sur la suppression. Pouvez-vous ajouter à votre réponse?
Bien qu'il soit également possible de visualiser le contenu de l'espace mémoire d'un programme pendant son fonctionnement. La suppression de la mémoire supprime simplement le pointeur vers la mémoire (un peu comme la suppression d'un fichier supprime le pointeur de fichier vers le fichier du système de fichiers). L'écrasement permet de le maintenir «sécurisé».
En supposant que l'écrasement, il l'écrase réellement, et ne déplace pas simplement le pointeur vers une nouvelle section de la mémoire avec les nouvelles valeurs (ce qui signifie que les anciennes données restent jusqu'à ce que la mémoire soit réutilisée, tout comme pour la supprimer).
Les pointeurs @lawtonfogle sont généralement des adresses mémoire, donc toutes les données que vous écrivez via le pointeur vont dans cet espace d'adressage. Bien que ce soit une idée intéressante. Votre méthode décrite ci-dessous n'est pas tout à fait la même chose que l'utilisation d'un pointeur.
@Desthro: Sauf si vous travaillez en mode réel (c'est-à-dire que vous écrivez un noyau de système d'exploitation), les pointeurs ne sont généralement qu'une adresse de mémoire virtuelle; seul le noyau a accès aux adresses mémoire réelles. Il est certainement possible pour le système d'exploitation de déplacer les deux pages de mémoire vers une adresse réelle différente lorsque la mémoire est écrasée, cela peut être fait sans changer l'adresse virtuelle. Cela se produit lors de l'échange par exemple.
@LieRyan montre l'âge de mes connaissances en programmation;)
Je pense que vous voudriez certainement que le mot-clé volatile s'assure que ce qui se passe est en fait un écrasement
@raptortech97 est-ce que «volatile» garantit réellement cela? Supposons qu'un processus soit suspendu et sa mémoire paginée avant que la variable sensible puisse être écrasée, puis il est repris plus tard. Il n'y a aucune garantie que la mémoire virtuelle sera paginée dans la même section de mémoire physique, n'est-ce pas? Dans un tel cas, «volatile» ne garantit pas un écrasement. Je pense. Je ne suis honnêtement pas sûr. (`volatile` empêche certaines optimisations du compilateur, je comprends cela, mais il semble que vous disiez qu'il fait plus que cela)
J'ai l'impression que ce que nous avons établi dans ces commentaires, c'est que les ordinateurs sont difficiles à «déjouer»
Lawtonfogle
2014-12-04 22:45:14 UTC
view on stackexchange narkive permalink

Vous stockez une valeur qui n'est plus utilisée? On dirait quelque chose qui serait optimisé, quel que soit l'avantage qu'il pourrait apporter.

De plus, vous ne pouvez pas réellement écraser les données en mémoire en fonction du fonctionnement du langage lui-même. Par exemple, dans un langage utilisant un garbage collector, il ne serait pas supprimé immédiatement (et cela suppose que vous n'ayez laissé aucune autre référence traîner).

Par exemple, en C #, je pense ce qui suit ne fonctionne pas.

  string secret = "my secret data"; ... beaucoup de travail ... string secret = "blahblahblah";  

"mes données secrètes" traîne jusqu'à ce que les ordures soient récupérées car elles sont immuables. Cette dernière ligne crée en fait une nouvelle chaîne et a un point secret vers elle. Cela n'accélère pas la vitesse à laquelle les données secrètes réelles sont supprimées.

Y a-t-il un avantage? En supposant que nous l'écrivions en assemblage ou dans un langage à faible levier afin que nous puissions nous assurer que nous écrasons les données, et nous mettons notre ordinateur en veille ou l'avons laissé allumé avec l'application en cours d'exécution, et nous avons notre RAM grattée par une femme de chambre diabolique, et evil maid a obtenu nos données RAM après que le secret a été écrasé mais avant qu'il ne soit simplement supprimé (probablement un très petit espace), et rien d'autre dans la RAM ou sur le disque dur ne révélerait ce secret ... alors je vois une augmentation possible en sécurité.

Mais le coût par rapport à l'avantage semble rendre cette optimisation de la sécurité très faible sur notre liste d'optimisations (et en dessous du point de «valable» sur la plupart des applications en général).

Je pourrais peut-être voir une utilisation limitée de cela dans des puces spéciales destinées à détenir des secrets pendant une courte période pour s'assurer qu'elles les conservent le plus rapidement possible, mais même dans ce cas, je ne suis pas sûr de tout avantage pour les coûts.

"probablement un très petit espace" - il n'est probablement pas si difficile de trouver des cas où le très petit espace correspond au moins à la durée de vie restante du processus. C'est-à-dire qu'il pourrait y avoir de la mémoire inutilisée qui, pour diverses raisons (et je ne parle pas seulement d'une fuite de mémoire), est susceptible de rester inutilisée pendant un certain temps. La bonne, après tout, analysera toute notre mémoire à la recherche de tout ce qui pourrait être utile. L'écraser au moment où il est devenu inutilisé fermerait donc une fenêtre. Mais comme vous le dites, nous ne pouvons toujours pas compter sur aucun avantage de sécurité de `mySecret = 0; monSecret = -1; `.
Si vous êtes préoccupé par l'optimisation de l'affectation, déclarez simplement la variable comme «volatile» (en C / C ++). Cela fera l'affaire. Si la valeur est une chaîne, écrasez le * contenu * de la chaîne au lieu d'utiliser une simple affectation.
De nombreuses astuces dépendantes de la langue qui ne se répercutent pas. Toutes les bibliothèques que vous utilisez qui stockent des données secrètes devront être vérifiées ligne par ligne pour s'assurer qu'elles le font. Et s'ils ne le font pas, réimplémentez-vous les bibliothèques mathématiques / cryptographiques? Le taux d'augmentation de la sécurité par ressource dépensée est si faible et le risque d'aggraver votre sécurité (via les réécritures de bibliothèque) est suffisamment élevé pour que je ne vois pas de cas d'utilisation justifié pour le développeur moyen.
Cort Ammon
2014-12-06 22:45:52 UTC
view on stackexchange narkive permalink

Vous avez besoin d'un modèle de menace

Vous ne devriez même pas commencer à penser à écraser les variables de sécurité tant que vous n'avez pas un modèle de menace décrivant les types de piratage que vous essayez d'éviter. La sécurité a toujours un coût. Dans ce cas, le coût est le coût de développement pour apprendre aux développeurs à gérer tout ce code supplémentaire pour sécuriser les données. Ce coût signifie qu'il est plus probable que vos développeurs commettent des erreurs, et que ces erreurs sont plus susceptibles d'être à l'origine d'une fuite que d'un problème de mémoire.

  • Peut l'attaquant accède à votre mémoire? Si tel est le cas, y a-t-il une raison pour laquelle vous pensez qu'ils ne pouvaient pas / ne renifleraient pas simplement la valeur avant que vous ne l'écrasiez? À quel type de délais l'attaquant a-t-il accès à votre mémoire
  • L'attaquant peut-il accéder aux vidages de mémoire? Cela vous dérange-t-il s'ils peuvent accéder à des données sensibles en échange d'être suffisamment bruyants pour provoquer un vidage de mémoire en premier lieu?
  • S'agit-il de open source ou de source fermée? Si c'est open source, vous devez vous soucier de plusieurs compilateurs, car les compilateurs optimiseront les choses comme les données écrasées tout le temps. Leur travail n'est pas d'assurer la sécurité. ( Pour un exemple concret, PasswordSafe de Schneier a des classes spécialisées pour protéger les données de mot de passe non chiffrées. Pour ce faire, il utilise les fonctions de l'API Windows pour verrouiller la mémoire et la forcer à être écrasée correctement plutôt que d'utiliser le compilateur pour le faire pour lui )
  • Est-ce un langage garbage collection? Savez-vous comment forcer VOTRE version particulière de votre garbage collector à se débarrasser de vos données?
  • Combien de tentatives l'attaquant peut-il faire pour obtenir des données sensibles avant que vous ne le remarquiez et l'interrompre par d'autres moyens (comme les pare-feu)?
  • Est-ce que cela s'exécute dans une machine virtuelle? Dans quelle mesure êtes-vous sûr de la sécurité de votre hyperviseur?
  • Un attaquant a-t-il un accès physique? Par exemple, Windows est plus qu'heureux d'utiliser un lecteur flash pour mettre en cache la mémoire virtuelle. Tout ce qu'un attaquant aurait à faire est de convaincre Windows de le pousser sur le lecteur flash. Lorsque cela se produit, il est VRAIMENT difficile de s'en débarrasser. Si difficile, en fait, qu'il n'y a pas de méthode reconnue pour effacer de manière fiable les données d'un lecteur flash.

Ces questions doivent être abordées avant d'envisager d'écraser des données sensibles. Essayer d'écraser des données sans aborder le modèle de thread est un faux sentiment de sécurité.

Un autre coût est plus de code et plus d'instructions à exécuter par l'ordinateur (plus lent), mais oui, bon point pour considérer la menace. Je pense qu'un pirate informatique accédant aux données secrètes de la RAM pendant que le programme est en cours d'exécution, ou même après, serait l'une des plus grandes menaces. Je pense que ce serait bien si vous pouviez dire au compilateur (ou à tout ce qui construit / exécute le langage que vous utilisez) de mettre à zéro les données lorsque cela est fait.
* "L'attaquant peut-il accéder à votre mémoire" * - eh bien, nous savons que l'attaquant utilisera la mémoire si elle est disponible. Et il n'a pas besoin d'être sur la machine locale. Par exemple, nous savons que [la NSA enregistrera le rapport d'erreurs Windows dans son système XKeyscore pour aider à obtenir un accès non autorisé] (http://en.wikipedia.org/wiki/Tailored_Access_Operations). Cela se produit que votre modèle de menace l'inclut ou non :)
Que cela se produise est très différent de savoir si vous voulez vraiment essayer de faire quoi que ce soit. Pour citer Kevin Mitnick, "Le seul ordinateur vraiment sécurisé est celui qui n'est pas connecté à Internet, débranché, stocké dans un bunker en béton sous terre avec des gardes armés dessus, et même alors je le vérifiais de temps en temps." Si vous voulez vraiment sécuriser votre programme NSA, vous aurez besoin de bien plus que StackExchange pour vous aider ;-)
Gilles 'SO- stop being evil'
2014-12-05 00:02:43 UTC
view on stackexchange narkive permalink

Oui, il est recommandé d'écraser les données particulièrement sensibles lorsque les données ne sont plus nécessaires, c'est-à-dire dans le cadre d'un destructeur d'objet (soit un destructeur explicite fourni par le langage, soit une action que le programme prend avant de désallouer l'objet). Il est même recommandé d'écraser des données qui ne sont pas en soi sensibles, par exemple pour remettre à zéro les champs de pointeur dans une structure de données qui n'est plus utilisée, et également mettre à zéro les pointeurs de sortie lorsque l'objet qu'ils pointent est libéré même si vous savez vous n'allez plus utiliser ce champ.

Une raison de le faire est au cas où les données fuiraient à travers des facteurs externes tels qu'un vidage de mémoire exposé, une image d'hibernation volée, un serveur compromis permettant une mémoire vidage des processus en cours d'exécution, etc. Les attaques physiques où un attaquant extrait les bâtons de RAM et utilise la rémanence des données sont rarement un problème sauf sur les ordinateurs portables et peut-être les appareils mobiles tels que les téléphones (où la barre est plus haute car la RAM est soudée), et même alors surtout dans des scénarios ciblés uniquement. La rémanence des valeurs écrasées n'est pas un problème: il faudrait un matériel très coûteux pour sonder l'intérieur d'une puce de RAM pour détecter toute différence de tension microscopique persistante qui pourrait être influencée par une valeur écrasée. Si vous vous inquiétez des attaques physiques sur la RAM, une plus grande préoccupation serait de vous assurer que les données sont surécrites dans la RAM et pas seulement dans le cache du processeur. Mais, encore une fois, c'est généralement une préoccupation très mineure.

La raison la plus importante d'écraser des données obsolètes est une défense contre les bogues du programme qui entraînent l'utilisation de la mémoire non initialisée, comme le tristement célèbre Heartbleed. Cela va au-delà des données sensibles car le risque ne se limite pas à une fuite des données: s'il y a un bogue logiciel qui provoque le déréférencement d'un champ de pointeur sans avoir été initialisé, le bogue est à la fois moins sujet à l'exploitation et plus facile à tracer si le champ contient tous les bits-zéro que s'il pointe potentiellement vers un emplacement mémoire valide mais dénué de sens.

Attention, les bons compilateurs optimiseront la remise à zéro s'ils détectent que la valeur n'est plus utilisée. Vous devrez peut-être utiliser une astuce spécifique au compilateur pour faire croire au compilateur que la valeur reste en cours d'utilisation et ainsi générer le code de remise à zéro.

Dans de nombreux langages avec gestion automatique, les objets peuvent être déplacés en mémoire sans remarquer. Cela signifie qu'il est difficile de contrôler les fuites de données périmées, à moins que le gestionnaire de mémoire lui-même n'efface la mémoire inutilisée (ce n'est souvent pas le cas, pour les performances). Du côté positif, les fuites externes sont généralement tout ce dont vous avez à vous soucier, car les langages de haut niveau ont tendance à empêcher l'utilisation de mémoire non initialisée (méfiez-vous des fonctions de création de chaînes dans les langages avec des chaînes mutables).

Par la façon dont, j'ai écrit «zéro» ci-dessus. Vous pouvez utiliser un modèle de bits autre que tous les zéros; all-zeros a l'avantage d'être un pointeur non valide dans la plupart des environnements. Un modèle de bits que vous connaissez est un pointeur invalide mais qui est plus distinctif peut être utile pour le débogage.

De nombreuses normes de sécurité imposent l'effacement des données sensibles telles que les clés. Par exemple, la norme FIPS 140-2 pour les modules cryptographiques l'exige même au niveau d'assurance le plus bas, ce qui à part cela ne nécessite que la conformité fonctionnelle et non la résistance aux attaques.

Normalement, les secrets ne sont pas directement exploités. Une bibliothèque cryptographique est utilisée (car l'implémentation d'un algorithme, même bon, est difficile et un bug d'implémentation peut rendre votre sécurité inutile). Alors, est-ce qu'on se limite aux bibliothèques qui ne changent que les données avant de les supprimer (éventuellement en éliminant la meilleure bibliothèque pour le travail)? Ou utilise-t-on une bibliothèque qui permet aux données de traîner jusqu'à leur suppression, perdant ainsi l'avantage de l'appliquer à son propre code?
Les bibliothèques cryptographiques @Lawtonfogle sont souvent écrites de manière à effacer au moins les clés après utilisation. C'est considéré comme une bonne hygiène parmi les implémenteurs de crypto et j'espère (bien que je n'ai pas de données fermes sur le sujet) qu'il soit corrélé avec des mesures de qualité raisonnables. Même si la bibliothèque ne le fait pas, vous pouvez souvent contrôler la gestion de la mémoire de la bibliothèque à partir de l'application.
Je dois admettre qu'il semble que les experts en sécurité qui écrivent des bibliothèques de crypto intègrent également d'autres pratiques de sécurité même si elles ne sont pas directement liées à la cryptographie elle-même. Mais vous voudrez vous assurer, espérons-le, qu'il est open source (si pour aucune autre raison que de vérifier son intégrité cryptographique).
"Si vous vous inquiétez des attaques physiques sur la RAM, une plus grande préoccupation serait de vous assurer que les données sont surécrites dans la RAM et pas seulement dans le cache du processeur." - Vous pouvez forcer la barrière de mémoire (au niveau le plus bas implémenté en tant qu'instruction du processeur) pour appliquer le vidage du cache du processeur à la RAM. Si le langage de programmation est de niveau supérieur, une façon de le faire est d'employer une primitive de partage de mémoire comme par exemple mutex (verrouiller, effacer, déverrouiller) qui utilise des barrières de mémoire dans le cadre de l'implémentation.
user10211
2014-12-16 18:48:16 UTC
view on stackexchange narkive permalink

Pour un ajout (espérons-le intéressant) au reste des réponses, de nombreuses personnes sous-estiment la difficulté à écraser correctement la mémoire avec C. Je vais citer en abondance le billet de blog de Colin Percival intitulé " Comment mettre à zéro un buffer ".

Le principal problème des tentatives naïves d'écrasement de la mémoire en C est l'optimisation du compilateur. La plupart des compilateurs modernes sont suffisamment "intelligents" pour reconnaître que les idoms courants utilisés pour l'écrasement de la mémoire ne modifient en fait pas le comportement observable du programme et peuvent être optimisés. Malheureusement, cela brise complètement ce que nous voulons accomplir. Certaines des astuces courantes sont décrites dans l'article de blog lié ci-dessus. Pire encore, une astuce qui fonctionne pour une version d'un compilateur peut ne pas nécessairement fonctionner avec un autre compilateur ou même une version différente du même compilateur. À moins que vous ne distribuiez des binaires uniquement , c'est une situation problématique.

Le seul moyen d'écraser de manière fiable la mémoire en C que je connaisse est le memset_s fonction. Malheureusement, cela n'est disponible qu'en C11, donc les programmes écrits pour les anciennes versions de C n'ont pas de chance.

La fonction memset_s copie la valeur de c (convertie en un caractère non signé) dans chacun des les n premiers caractères de l'objet pointé par l'art. Contrairement à memset, tout appel à memset_s doit être évalué strictement selon les règles de la machine abstraite, comme décrit au 5.1.2.3. Autrement dit, tout appel à memset_s supposera que la mémoire indiquée par s et n peut être accessible dans le futur et doit donc contenir les valeurs indiquées par c.

Indéniablement, Colin Percival est de l'opinion que l'écrasement de la mémoire ne suffit pas. À partir d'un article de blog de suivi intitulé " La remise à zéro des tampons est insuffisante", il déclare

Avec un peu de soin et un compilateur coopératif, nous pouvons mettre à zéro un tampon - mais ce n'est pas ce dont nous avons besoin. Ce que nous devons faire, c'est mettre à zéro tous les emplacements où des données sensibles pourraient être stockées. Rappelez-vous, la raison pour laquelle nous avions des informations sensibles en mémoire en premier lieu était pour que nous puissions les utiliser; et cette utilisation a presque certainement entraîné la copie de données sensibles sur la pile et dans des registres.

Il continue et donne l'exemple des implémentations AES utilisant le jeu d'instructions AESNI sur les plates-formes x86 qui fuient des données dans les registres.

Il prétend que,

Il est impossible de mettre en œuvre en toute sécurité un système de cryptage fournissant un secret de transmission en C.

A affirmation troublante en effet.

Nous vous remercions de vos idées! Ce serait certainement bien si les compilateurs C et C ++ incluaient une option pour mettre à zéro la mémoire quand elle est hors de portée (ou peut-être un moyen d'indiquer au compilateur quelles variables supprimer en toute sécurité).
Ari Trachtenberg
2014-12-05 09:37:45 UTC
view on stackexchange narkive permalink

Il est important d'écraser les données sensibles immédiatement après cela, car sinon:

  • Les données restent dans la pile jusqu'à ce qu'elles soient écrasées et peuvent être visualisées avec un débordement de trame d'une procédure différente.
  • Les données sont sujettes à un grattage de mémoire.

En effet, si vous regardez le code source des applications sensibles à la sécurité (ex openssh), vous constaterez qu'il met à zéro soigneusement les données sensibles après utilisation.

Il est également vrai que les compilateurs peuvent essayer d'optimiser l'écrasement et, même si ce n'est pas le cas, il est important de savoir comment les données sont stockées physiquement (par exemple, si le secret est stocké sur SSD, l'écrasement risque de ne pas effacer l'ancien contenu en raison du nivellement de l'usure).

Andy Dent
2014-12-07 11:49:37 UTC
view on stackexchange narkive permalink

L'exemple original montre une variable de pile parce que c'est un type int natif.

L'écrasement est une bonne idée sinon elle persiste dans la pile jusqu'à ce qu'elle soit écrasée par autre chose.

Je suppose que si vous êtes en C ++ avec des objets de tas ou des types natifs C alloués via des pointeurs et malloc, ce serait une bonne idée de

  1. Utiliser volatile
  2. Utilisez des pragmas pour entourer le code en utilisant cette variable et désactiver les optimisations.
  3. Si possible, n'assemblez le secret que dans des valeurs intermédiaires plutôt que dans des variables nommées, donc il n'existe que pendant les calculs.

Sous la JVM ou C #, je pense que tous les paris sont ouverts.

* "Si possible, n'assemblez le secret que dans des valeurs intermédiaires plutôt que dans des variables nommées" * Cela n'a pas beaucoup de sens car la plupart des binaires compilés par version n'incluent pas d'informations de dénomination. Si je désassemble une application compilée C ++, je pourrai dire quelles instructions elle exécute, mais je ne pourrai presque certainement pas dire de noms de variables.
Je me trompe peut-être, mais je pensais à l'endroit où les valeurs intermédiaires sont stockées par opposition à toute valeur unique attribuée à une variable. Si vous mettez une constante dans votre code et que vous l'assignez à une variable, à un moment donné, cette constante est liée à une valeur dans un bloc statique. Les valeurs intermédiaires existent soit dans les registres, soit en interne dans le cache de puce. Si vous calculiez une sorte de clé comme valeur intermédiaire et compariez ensuite ce résultat à une valeur d'un service, le tout est beaucoup plus transitoire.
ratchet freak
2014-12-05 18:00:31 UTC
view on stackexchange narkive permalink

Il est possible que le morceau de mémoire ait été paginé avant que vous ne le supprimiez, selon la façon dont la distribution d'utilisation dans le fichier d'échange est lue, les données peuvent y vivre pour toujours .

Pour réussir à supprimer le secret de l'ordinateur, vous devez d'abord vous assurer que les données n'atteignent jamais la mémoire persistante en épinglant les pages. Ensuite, assurez-vous que le compilateur n'optimise pas les écritures dans la mémoire à supprimer.

PaulOverflow
2014-12-17 13:20:34 UTC
view on stackexchange narkive permalink

En fait, la réponse est oui, vous devriez probablement l'écraser avant de le supprimer. Si vous êtes un développeur d'applications Web, vous devriez probablement écraser toutes les données avant d'utiliser les fonctions delete ou free .

Exemple de comment ce bogue peut être exploité:

L'utilisateur peut insérer des données malveillantes dans le champ de saisie. Vous continuez les données puis appelez la fonction free de la mémoire allouée sans l'écraser, de sorte que les données resteront dans la mémoire. Ensuite, l'utilisateur fait tomber votre application Web (par exemple en téléchargeant une très grande image ou quelque chose comme ça) et le système UNIX sécurisera le vidage de la mémoire centrale dans le noyau core ou core. Fichier <pid> . Ensuite, si l'utilisateur peut brutaliser le <pid> , ce qui ne prendra pas trop de temps, et le fichier de vidage principal sera interprété comme un shell Web, car il contient des données malveillantes de l'utilisateur.

mincewind
2014-12-17 13:52:09 UTC
view on stackexchange narkive permalink

Int secret = 13123 n'est-il pas une constante à portée locale?

Vous ne devriez pas être trop absorbé par ce que vous écrivez est loin d'être intéressant à lire. En fait, je suggérerais, dans un petit conseil à contre-courant, que vous le laissiez délibérément lisible. Et de plus, remplissez-le au hasard avec des chaînes qui sont corrélées dans le temps, qui ne sont pas appelées de manière standard.

De cette façon, si vous consultez des sites Web sombres pour savoir si vous avez été compromis, vous pouvez dire précisément comment cela a été fait. Puisqu'un db dump est séparé d'un scraper dump.



Ce Q&R a été automatiquement traduit de la langue anglaise.Le contenu original est disponible sur stackexchange, que nous remercions pour la licence cc by-sa 3.0 sous laquelle il est distribué.
Loading...