Question

Je veux créer un allocateur qui fournit de la mémoire avec les attributs suivants:

  • ne peut pas être transférées sur le disque.
  • est incroyablement difficile d'accès par l'intermédiaire d'un joint le débogueur

L'idée est que cela va contenir des informations sensibles (comme des informations sur la licence) qui devrait être inaccessibles à l'utilisateur.J'ai fait de l'habitude de la recherche en ligne et a demandé à quelques autres personnes à ce sujet, mais je ne peux pas trouver une bonne place sur ce problème.

Les mises à jour

Josh mentionne l'utilisation de VirtualAlloc pour définir la protection sur l'espace de la mémoire.J'ai créé un allocateur personnalisé ( voir ci-dessous ), j'ai trouvé l'utilisation de la VirtualLock la fonction limite la quantité de mémoire je peux allouer.Cela semble être par la conception de si.Depuis que je suis à l'aide de petits objets, ce n'est pas un problème.

//
template<class _Ty>
class LockedVirtualMemAllocator : public std::allocator<_Ty>
{
public:
    template<class _Other>
    LockedVirtualMemAllocator<_Ty>& operator=(const LockedVirtualMemAllocator<_Other>&)
    {   // assign from a related LockedVirtualMemAllocator (do nothing)
        return (*this);
    }

    template<class Other>
    struct rebind {
        typedef LockedVirtualMemAllocator<Other> other;
    };

    pointer allocate( size_type _n )
    {
        SIZE_T  allocLen = (_n * sizeof(_Ty));
        DWORD   allocType = MEM_COMMIT;
        DWORD   allocProtect = PAGE_READWRITE;
        LPVOID pMem = ::VirtualAlloc( NULL, allocLen, allocType, allocProtect );
        if ( pMem != NULL ) {
            ::VirtualLock( pMem, allocLen );
        }
        return reinterpret_cast<pointer>( pMem );
    }
    pointer allocate( size_type _n, const void* )
    {
        return allocate( _n );
    }

    void deallocate(void* _pPtr, size_type _n )
    {
        if ( _pPtr != NULL ) {
            SIZE_T  allocLen = (_n * sizeof(_Ty));
            ::SecureZeroMemory( _pPtr, allocLen );
            ::VirtualUnlock( _pPtr, allocLen );
            ::VirtualFree( _pPtr, 0, MEM_RELEASE );
        }
    }
};

et est utilisé

 //a memory safe std::string
 typedef std::basic_string<char, std::char_traits<char>, 
                           LockedVirtualMemAllocato<char> > modulestring_t;

Ted Percival mentions mlock, mais je n'ai pas de mise en œuvre de que encore.

J'ai trouvé Pratique de la Cryptographie par Neil Furguson et Bruce Schneier très utile aussi bien.

Était-ce utile?

La solution

Vous ne pouvez pas vraiment les protéger contre l'accès à la mémoire.Vous pouvez probablement vous empêcher de pagination si vous exécutez en tant qu'administrateur ou que le système, mais vous ne pouvez pas empêcher l'administrateur système ou à partir de la lecture de votre mémoire.Même si tu arrivais à les bloquer complètement les autres processus à partir de la lecture de votre mémoire (que vous ne pouvez pas), un autre processus pourrait encore fait injecter un nouveau thread dans votre processus et de lire la mémoire de cette façon.

Même si vous pourrait d'une certaine manière complètement le verrouillage de vos processus et de garantir que le système d'exploitation serait jamais permettre à quiconque d'accéder à votre processus, vous n'avez toujours pas d'une protection complète.L'ensemble de l'OS pourrait être exécuté dans une machine virtuelle, ce qui pourrait être mis en pause et inspectés à tout moment.

Vous ne peut pas protéger le contenu de la mémoire de la part du propriétaire du système.Hollywood et l'industrie de la musique ont été mal pour cela pendant des années.Si c'était possible, ils avaient déjà le faire.

Autres conseils

Sur les systèmes Unix, vous pouvez utiliser mlock(2) pour verrouiller des pages de mémoire dans la RAM, les empêchant d'être paginé.

mlock() et mlockall() respectivement de verrouillage de la partie ou de la totalité de l'appel processus de l'espace d'adressage virtuel en mémoire vive, la prévention que de la mémoire de paginées de l'espace de pagination.

Il y a une limite à la quantité de mémoire de chaque processus peut se verrouiller, il peut être démontré avec ulimit -l et est mesurée en kilo-octets.Sur mon système, la limite par défaut est de 32 kio par processus.

Si vous êtes en développement pour Windows, il existe des moyens que vous pouvez restreindre l'accès à la mémoire, mais absolument bloquer les autres n'est pas faisable.Si vous êtes l'espoir de garder un secret, lu Écriture De Code Sécurisé - qui traite de ce problème plus en détail, mais sachez que vous n'avez aucun moyen de savoir si votre code est en cours d'exécution sur une machine réelle ou une machine virtuelle.Il y a un tas de Win32 API de trucs à faire face avec la crypto qui gère ce genre de chose, y compris l'entreposage sécuritaire des secrets - le livre parle de ça.Vous pouvez regarder en ligne Microsoft CyproAPI pour plus de détails;les OS les concepteurs reconnaissent ce problème et la nécessité de maintenir le texte en clair sécurisé (encore une fois, lisez Écriture De Code Sécurisé).

La fonction de l'API Win32 VirtualAlloc est au niveau de l'OS allocateur de mémoire.Il vous permet de configurer la protection d'accès;ce que vous pourriez faire est de réserver l'accès à la PAGE_GUARD ou PAGE_NOACCESS, et le retourner à l'accès à quelque chose de plus convivial lors de votre programme de lectures, et de le remettre par la suite, mais c'est simplement une bosse de vitesse si quelqu'un est en train d'essayer vraiment dur à coup d'oeil à ce que votre secret.

En résumé, regardez la crypto Api sur votre plate-forme, ils vont régler le problème mieux que quelque chose vous hack vous-même.

Prenons un peu à la fois:

Je veux créer un allocateur qui fournit de la mémoire avec les éléments suivants attributs:

C'est assez juste.

* cannot be paged to disk.

Ça va être dur.Pour autant que je suis conscient, vous ne pouvez pas désactiver la Pagination Virtuelle qu'il soit géré par l'OS.Si il existe un moyen, alors vous serez à la spéléologie dans les entrailles de l'OS.

* is incredibly hard to access through an attached debugger

Vous pourriez courir à travers PGP et de le stocker crypté dans la mémoire et décrypter ce qu'il fallait.Massif des performances.

L'idée est que cela va contenir des informations sensibles (comme la licence de l'information) qui devrait être inaccessible à l'utilisateur.Je l'ai fait l'habitude de la recherche en ligne et a demandé à un quelques autres personnes à ce sujet, mais je impossible de trouver une bonne place sur ce problème.

Garder toutes les informations de la machine.Sérieusement.Ne pas stocker des informations sensibles dans la mémoire.Écrire une coutume supprimer routine qui supprimera automatiquement toutes les données de toutes les allocations que vous effectuez.Ne jamais permettre l'accès général à une machine avec des matériaux sensibles sur elle.Si vous effectuez db accès, assurez-vous que tous les accès sont désinfectés avant la cuisson.Seulement les gens log-ins sont autorisés à accéder.Pas de groupe d'accès.

Sur une note de côté, ce que d'autres méthodes sont il y a des accès à la mémoire d'un procédé autre que de fixer un débogueur?

Prendre un dump de la mémoire.

installer Libsodium, l'utilisation de mécanismes d'allocation par #, y compris <sodium.h>

Gardé les allocations de tas

Plus lent que malloc() et ses amis, ils ont besoin de 3 ou 4 pages de mémoire virtuelle.

void *sodium_malloc(size_t size);

Allouer de la mémoire pour stocker des données sensibles à l'aide de sodium_malloc() et sodium_allocarray().Vous devez d'abord appeler sodium_init() avant d'utiliser ces tas de gardes.

void *sodium_allocarray(size_t count, size_t size);

L' sodium_allocarray() la fonction retourne un pointeur à partir de laquelle compter les objets qui sont de la taille octets de mémoire chacun peut être consulté.Il offre les mêmes garanties que sodium_malloc() mais protège également contre les débordements quand l'arithmétique count * size dépasse SIZE_MAX.

Ces fonctions d'ajouter des pages de garde autour de la protégée de données afin de la rendre moins susceptibles d'être accessible dans un heartbleed-tout comme le scénario.

En outre, la protection des zones de mémoire allouées de cette façon peut être changé en utilisant le verrouillage de la mémoire des opérations: sodium_mprotect_noaccess(), sodium_mprotect_readonly() et sodium_mprotect_readwrite().

Après sodium_malloc vous pouvez utiliser sodium_free() pour déverrouiller et de libérer de la mémoire.À ce stade de la mise en œuvre d'envisager une réinitialisation de la mémoire après utilisation.

zéro la mémoire après utilisation

void sodium_memzero(void * const pnt, const size_t len);

Après utilisation, les données sensibles doivent être remplacées, mais memset() et écrit à la main le code peut être silencieusement supprimés par une optimisation du compilateur ou l'éditeur de liens.

Le sodium_memzero() la fonction essaie de effectivement zéro len octets commençant à l'pnt, même si des optimisations sont appliqués pour le code.

le verrouillage de l'allocation de mémoire

int sodium_mlock(void * const addr, const size_t len);

L' sodium_mlock() la fonction de serrures à moins len octets de mémoire commençant à l'addr.Cela peut aider à éviter la permutation des données sensibles sur le disque.

int sodium_mprotect_noaccess(void *ptr);

Le sodium_mprotect_noaccess() la fonction rend une région alloués à l'aide de sodium_malloc() ou sodium_allocarray() inaccessible.Il ne peut pas être lu ou écrit, mais les données sont conservées.Cette fonction peut être utilisée pour rendre confidentielles les données inaccessibles, sauf lorsqu'ils sont effectivement nécessaires pour une opération spécifique.

int sodium_mprotect_readonly(void *ptr);

Le sodium_mprotect_readonly() de la fonction de la marque d'une région alloués à l'aide de sodium_malloc() ou sodium_allocarray() en lecture seule.De tenter de modifier les données de provoquer l'arrêt du processus.

int sodium_mprotect_readwrite(void *ptr);

L' sodium_mprotect_readwrite() la fonction de la marque d'une région alloués à l'aide de sodium_malloc() ou sodium_allocarray() que de lecture et d'écriture, après avoir été protégées à l'aide de sodium_mprotect_readonly() ou sodium_mprotect_noaccess().

Ce que vous demandez est gérée au niveau de l'OS.Une fois les données dans votre programme, il est susceptible d'être paginées.

Pour accéder à la mémoire, un individu motivé pouvez joindre un matériel débogueur.

@graham

Vous pourriez courir à travers PGP et de le stocker crypté dans la mémoire et décrypter ce qu'il fallait.Massif des performances.

Ensuite, vous auriez à tenir la clé en mémoire.Que serait rendre un peu plus difficile, mais certainement pas impossible.Toute personne motivée sera encore réussi à obtenir les données de la mémoire.

Votre meilleur pari est de mettre en place quelque chose de similaire .NET SecureString classe, et d'être très prudent à zéro tous en clair des copies de vos données dès que vous avez terminé (n'oubliez pas de nettoyage, même lorsque les exceptions sont jetés).Une bonne façon de le faire avec std::string et telle est d'utiliser un allocateur personnalisé.

Sur Windows, si vous utilisez CryptProtectMemory (ou RtlEncryptMemory pour les systèmes plus anciens), le cryptage de mot de passe est stocké dans la non-paginable (noyau?) de la mémoire.Dans mes tests, ces fonctions sont sacrément rapide, esp.en tenant compte de la protection qu'ils sont en vous donnant.

Sur d'autres systèmes, j'aime utiliser Blowfish puisque c'est un bon mélange entre la vitesse et la force.Dans ce dernier cas, vous aurez à générer de façon aléatoire à votre propre mot de passe (16+ octets de l'entropie pour Blowfish) au démarrage du programme.Malheureusement, il n'y a pas beaucoup que vous pouvez faire pour protéger le mot de passe sans le support de l'OS, bien que vous pourriez utiliser générale de la dissimulation de l'techniques pour intégrer une codé en dur de sel de valeur dans votre exécutable que vous pouvez combiner avec le mot de passe (chaque petit peu aide).

Dans l'ensemble, cette stratégie n'est qu'une partie d'une plus vaste de la défense en profondeur.Aussi garder à l'esprit que de simples bugs tels que les dépassements de la mémoire tampon et pas de programme d'assainissement de l'entrée reste de loin le plus commun des vecteurs d'attaque.

Vous ne pouvez pas protéger le contenu de la mémoire de la part du propriétaire du système.Hollywood et l'industrie de la musique ont été mal pour cela pendant des années.Si c'était possible, ils avaient déjà le faire.

Avez-vous eu un coup d'oeil à Vista (et supérieur) Les Processus Protégés (direct .doc télécharger).Je crois que le système d'exploitation de l'exécution de la protection est une gracieuseté de l'industrie du divertissement.

@Derek:Oh, mais avec l'informatique de confiance, vous pouvez utiliser mémoire curtaining!:-P</devils-advocate>

@rdo

J'espérais vraiment que c'était possible, et que je n'avais simplement pas encore trouvé.Votre exemple m'a fait réaliser que c'est exactement ce que nous essayons de faire, - d'autoriser uniquement l'accès à des dossiers dans le cadre de notre programme et de préserver la propriété intellectuelle.

Je suppose que je dois accepter qu'il n'y a pas vraiment de moyen sécurisé pour stocker quelqu'un fichier sur un autre ordinateur, surtout si à un certain moment de l'accès à ce fichier par le propriétaire.

C'est certainement le problème.Vous pouvez stocker quelque chose en toute sécurité aussi longtemps que vous n'avez jamais accorder l'accès, mais dès que vous accorder l'accès à votre contrôle est allé.Vous pouvez la rendre un peu plus difficile, mais c'est tout.

@Chris

Oh, mais avec l'informatique de confiance, vous pouvez utiliser la mémoire curtaining!:-P

Mais alors, vous devez réellement être prêt à payer pour un ordinateur de quelqu'un d'autre possède.:p

@Derek Parc

Il ne se dit plus difficile, pas impossible.PGP, il serait plus difficile, pas impossible.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top