Secure Memory Alocator în C ++

Vreau să creez un alocator care oferă memorie cu următoarele atribute:

  • nu pot fi pagerate pe disc.
  • este incredibil de greu de accesat printr-un depanator atașat

Ideea este că acest lucru va conține informații sensibile (cum ar fi informații despre licență) care ar trebui să fie inaccesibile utilizatorului. Am facut cercetarile obisnuite online si am intrebat cativa alti oameni despre acest lucru, dar nu pot gasi un bun inceput in aceasta problema.

Actualizări

Josh mentions using VirtualAlloc to set protection on the memory space. I have created a custom allocator ( shown below ) I have found the using the VirtualLock function it limits the amount of memory I can allocate. This seems to be by design though. Since I am using it for small objects this is not a problem.

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

    template
    struct rebind {
        typedef LockedVirtualMemAllocator 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( 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 );
        }
    }
};

și este utilizat

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

Ted Percival mentions mlock, but I have no implementation of that yet.

Am găsit Criptografia practică de Neil Furguson și Bruce Schneier destul de util.

0
fr hi bn

13 răspunsuri

@Derek: Oh, dar cu ajutorul computerului de încredere, puteți folosi perdea de memorie ! :-P

0
adăugat

Ceea ce cereți este tratat la nivelul sistemului de operare. Odată ce datele se află în programul dvs., acestea pot fi pagerate.

Pentru a accesa memoria, un individ motivat poate atașa un program de depanare hardware.

0
adăugat

Să luăm acest lucru la un moment dat:

Vreau să creez un alocator care să   oferă memorie cu următoarele   atribute:

E destul de corect.

  * nu poate fi pagerat pe disc.
 

Va fi greu. Din câte știu, nu puteți dezactiva Virtual Paging deoarece este gestionat de sistemul de operare. Dacă există o cale, atunci veți fi spelunking în intestinelor sistemului de operare.

  * este incredibil de greu de accesat printr-un depanator atașat
 

Ați putea să-l rulați prin PGP și să-l stocați criptat în memorie și să nu-l criptați după cum este necesar. Performanță lovită masiv.

Ideea este că acest lucru va conține   (cum ar fi licența   informații) care ar trebui să fie   inaccesibil utilizatorului. am făcut   de cercetare online obișnuită și a cerut o   puțini oameni despre asta, dar eu   nu poate găsi un loc bun în această privință   problema.

Păstrați toate informațiile sensibile de pe mașină. Serios. Nu păstrați informații sensibile în memorie. Scrieți o rutină de ștergere personalizată care va elimina automat toate datele din orice alocări pe care le efectuați. Nu permiteți niciodată accesul general la o mașină cu materiale sensibile pe ea. Dacă efectuați acces db, asigurați-vă că toate accesul este dezinfectat înainte de ardere. Numai persoanele care au log-in-uri specifice au permisiunea de acces. Nici un acces general la grup.

Pe o notă laterală, ce alte metode sunt   acolo de a accesa memoria unui a   proces decât atașarea a   debugger?

Luând o groapă de memorie.

0
adăugat
Puneți-l pe o mașină diferită. Dacă lăsați ceva pe aparatul sensibil, atunci un utilizator rău intenționat îl poate inspecta și decripta. Dacă aduceți informațiile atunci când este necesar și doar le decriptați atunci când sunt accesate și apoi le eliminați imediat după aceea devine mai greu. Cu toate acestea, niciun dispozitiv nu este complet protejat. Cineva suficient de hotărât să o eludeze. Ceea ce trebuie să faceți este să faceți destul de greu pentru a păcăli 99,9%, dar nu suficient pentru a deranja aceleași 99,9%.
adăugat autor graham.reeds, sursa
"Păstrați toate informațiile sensibile de pe mașină." Iartă-mă dacă înțeleg greșit, dar ce ar trebui să faceți atunci cu informații sensibile? Vrei să scapi de calculatoare și să o faci manual?
adăugat autor Parker Kemp, sursa

@ Derek Park

El a spus doar mai greu, nu imposibil. PGP ar face mai greu, nu imposibil.

0
adăugat

Dacă dezvoltați pentru Windows, există modalități prin care puteți restricționa accesul la memorie, dar blocarea absolută a altora nu este posibilă. Dacă speră să păstrați un secret secret, citiți Scrierea codului securizat - care abordează această problemă într-o anumită perioadă de timp, dar trebuie să știți că nu aveți cum să știți dacă codul dvs. rulează pe o mașină reală sau pe o mașină virtuală. Există o grămadă de chestii API pentru Win32 care să se ocupe de cripto-ul care gestionează astfel de lucruri, inclusiv stocarea în siguranță a secretelor - cartea discută despre asta. Puteți să consultați Microsoft CyproAPI online pentru Detalii; proiectanții sistemului de operare recunosc această problemă și necesitatea de a păstra securitatea textului clar (din nou, citiți Scrierea codului securizat ).

Funcția API Win32 VirtualAlloc este alocatorul de memorie de nivel OS. Acesta vă permite să setați protecția de acces; Ce ai putea face este setat acces la PAGE_GUARD sau PAGE_NOACCESS , și flip accesul la ceva mai prietenos în timp ce programul citește, și resetați-l după aceea, dar asta e doar o cocoasa de viteză în cazul în care cineva încearcă cu greu să vă uite la secretul tău.

În concluzie, uitați-vă la API-urile de tip crypto de pe platforma dvs., vor aborda problema mai bine decât ceva pe care l-ați hacked.

0
adăugat
CryptProtectMemory, este un alt apel API care vă poate ajuta. Nu sunt sigur exact ce face, ci comportamentul anunțat pentru a opri alte procese de la citirea paginii.
adăugat autor deft_code, sursa
Implementarea Mono SecureString este o referință bună în acest sens. În principiu, trebuie să criptați totul în memorie, astfel încât să nu se afișeze pe disc în text. Protecția datelor din memorie este mai puțin importantă. Folosesc Blowfish în clasa mea SecureString încrucișată atunci când sistemul de operare nu suportă nativă memoria criptată.
adăugat autor kgriffs, sursa

Nu puteți proteja împotriva accesului la memorie. Probabil că puteți preveni activarea paginilor dacă executați ca administrator sau ca sistem, dar nu puteți împiedica administratorul sau sistemul să vă citească memoria. Chiar dacă ați putea bloca complet alte procese din citirea memoriei (pe care nu o puteți face), un alt proces ar putea injecta încă un fir nou în procesul dvs. și să citească memoria în acest fel.

Chiar dacă ați reuși să închideți complet procesul și să vă asigurați că sistemul de operare nu permite altcuiva să acceseze procesul dvs., tot nu aveți protecție completă. Întregul sistem de operare ar putea funcționa într-o mașină virtuală, care ar putea fi întreruptă și inspectată în orice moment.

Nu puteți proteja conținutul memoriei de la proprietarul sistemului. Hollywood și industria muzicală au fost durere pentru acest lucru de ani de zile. Dacă ar fi posibil, ar fi făcut-o deja.

0
adăugat
Dacă/din moment ce acest lucru este adevărat, cum funcționează PlayReady (<3.0), Widevine, etc. fără a fi spart?
adăugat autor davidkomer, sursa
ce zici de codarea datelor cu o cheie înainte de a ieși din CPU?
adăugat autor v.oddou, sursa

@graham

Aveți posibilitatea să rulați-l prin PGP și să îl stocați criptat în memorie și să îl nu-l criptați după cum este necesar. Performanță puternică lovită.

Apoi va trebui să țineți cheia în memorie. Asta ar face mai greu, dar cu siguranță nu imposibil. Oricine este motivat va reuși să obțină datele din memorie.

0
adăugat

@roo

Speram că este posibil și că tocmai nu l-am găsit încă. Exemplul dvs. a făcut doar să-mi dau seama că asta este exact ceea ce încercăm să facem - permitem doar accesul la fișiere în contextul programului nostru și astfel păstrăm IP-ul.

     

Cred că trebuie să accept că nu există nici o modalitate sigură de a stoca fișierele cuiva pe un alt computer, mai ales dacă la un moment dat este permis accesul acelui fișier de către proprietar.

Aceasta este cu siguranță problema. Puteți stoca ceva în siguranță, atâta timp cât nu acordați niciodată acces, dar de îndată ce acordați accesul, controlul dumneavoastră este dispărut. Puteți face ceva mai dificil, dar asta e tot.

0
adăugat

@Chris

Oh, dar cu calculul de încredere, poți folosi perdele de memorie! :-P

Dar atunci trebuie să fiți dispuși să plătiți pentru un computer pe care îl deține altcineva. : p

0
adăugat

Cel mai bun pariu este să implementați ceva similar cu clasa .NET a SecureString și să fiți foarte atent să eliminați orice copie fără text a datelor dvs., de îndată ce ați terminat (nu uitați să faceți curățarea chiar și atunci când sunt extrase excepții). O modalitate buna de a face acest lucru cu std :: string si astfel este sa folositi un alocator personalizat .

Pe Windows, dacă utilizați CryptProtectMemory (sau RtlEncryptMemory pentru sistemele mai vechi), parola de criptare este stocată în memorie nerecuperabilă (kernel?). În testarea mea, aceste funcții sunt destul de darn fast, esp. luând în considerare protecția pe care o acordă dumneavoastră.

Pe alte sisteme, îmi place să folosesc Blowfish deoarece este un amestec bun între viteză și putere. În acest din urmă caz, va trebui să genereze aleatoriu propria parolă (16+ bytes de entropie pentru Blowfish) la pornirea programului. Din păcate, nu există o mulțime puteți face pentru a proteja acea parolă, fără suport sistem de operare, deși s-ar putea folosi tehnici generale de confuzie pentru a încorpora o valoare hard-coded sare în executabil pe care le puteți combina cu parola (fiecare pic ajută).

În ansamblu, această strategie este doar o parte a unei abordări mai ample de apărare în profunzime. De asemenea, țineți cont de faptul că bug-uri simple, cum ar fi depășirea tamponului și nu dezinfectarea programelor, rămân de departe cele mai frecvente vectori de atac.

0
adăugat

Pe sistemele Unix puteți utiliza mlock (2) pentru a bloca paginile de memorie în memoria RAM, împiedicându-le fiind pagerat.

mlock() și mlockall() respectiv, blochează o parte sau toate apelurile   procesul de spațiu de adrese virtuale în RAM, împiedicând acea memorie de la   fiind pagerat în zona de swap.

Există o limită a memoriei pe care fiecare proces poate să o blocheze, poate fi afișată cu ulimit -l și este măsurată în kilobyte. În sistemul meu, limita prestabilită este de 32 kiB pe proces.

0
adăugat

Nu puteți proteja conținutul memoriei de la proprietarul sistemului.   Hollywood și industria muzicală au fost durere pentru acest lucru de ani de zile.   Dacă ar fi posibil, ar fi făcut-o deja.

Ați aruncat o privire la Vista (și mai sus) Procese protejate (direct descărcare doc ). Cred că protecția impusă de sistemul de operare este o favoare a industriei de divertisment.

0
adăugat

install Libsodium, use allocation mechanisms by #including

Alocări de heapuri păstrate

Mai încet decât malloc() și prieteni, au nevoie de 3 sau 4 pagini suplimentare de memorie virtuală.

void *sodium_malloc(size_t size);

Alocați memoria pentru a stoca date sensibile folosind sod_malloc() și sodium_allocarray() . Va trebui să inițializați codul sodium_init() înainte de a utiliza aceste gărzi.

void *sodium_allocarray(size_t count, size_t size);

Funcția sodium_allocarray() returnează un pointer din care pot fi accesate numerele de obiecte care sunt octeți de dimensiune de memorie. Oferă aceleași garanții ca sodium_malloc() , dar protejează împotriva depășirilor aritmetice atunci când count * size depășește SIZE_MAX .

Aceste funcții adaugă pagini de gardă în jurul datelor protejate pentru a face mai puțin probabil ca acestea să fie accesibile într-un scenariu asemănător cu inima.

În plus, protecția pentru regiunile de memorie alocate în acest fel poate fi modificată utilizând operațiile de memorare a blocării: sodium_mprotect_noaccess() , sodium_mprotect_readonly() code>.

După sod_malloc , puteți utiliza sod_free() pentru a debloca și a dezauza memoria. În acest moment în implementarea dvs., luați în considerare reducerea memoriei după utilizare.

zero după utilizare

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

După utilizare, datele sensibile ar trebui să fie suprascrise, însă memset() și codul scris manual pot fi eliminate în mod silențios de un compilator de optimizare sau de linker.

Funcția sod_memzero() încearcă să elimine efectiv numai octeți începând de la pnt, chiar dacă se aplică coduri la optimizări.

blocarea alocării memoriei

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

Funcția sod_mlock() blochează cel puțin lenți de octeți de memorie care încep de la addr. Acest lucru poate ajuta la evitarea schimbării datelor sensibile pe disc.

int sodium_mprotect_noaccess(void *ptr);

Funcția sodium_mprotect_noaccess() face ca o regiune alocată folosind sod_malloc() sau sodium_allocarray() să fie inaccesibilă. Nu poate fi citit sau scris, dar datele sunt păstrate. Această funcție poate fi utilizată pentru a face datele confidențiale inaccesibile, cu excepția faptului că sunt necesare pentru o anumită operație.

int sodium_mprotect_readonly(void *ptr);

Funcția sodium_mprotect_readonly() marchează o regiune alocată utilizând sod_malloc() sau sodium_allocarray() ca fiind numai pentru citire. Încercarea de a modifica datele va determina încetarea procesului.

int sodium_mprotect_readwrite(void *ptr);

Funcția sodium_mprotect_readwrite() marchează o regiune alocată utilizând codul sodium_malloc() sau sodium_allocarray() sodium_mprotect_readonly() sau sodium_mprotect_noaccess() .

0
adăugat