Programare defensivă

Când scrieți un cod, programați în mod conștient defensiv pentru a asigura o calitate ridicată a programului și pentru a evita posibilitatea ca codul dvs. să fie exploatat în mod malefic, de ex. prin exploatări de tampon de depășire sau prin injectare de cod?

Care este nivelul minim al calității pe care îl veți aplica întotdeauna codului dvs.?

0
fr hi bn

13 răspunsuri

Voi lua o altă definiție a programării defensive, ca cea recomandată de Eficient Java de Josh Bloch. În carte, el vorbește despre modul în care se pot gestiona obiectele mutable pe care apelanții le transmit codului dvs. (de exemplu, în setteri) și obiecte mutabile pe care le transmiteți apelanților (de exemplu, în getters).

  • Pentru setteri, asigurați-vă că ați clonat orice obiecte mutați și stocați clona. În acest fel, apelanții nu pot schimba obiectul transmis după ce a rupt invarianții programului.
  • Pentru getters, fie returnează o vizualizare imutabilă a datelor interne, dacă interfața o permite; sau întoarce o clonă a datelor interne.
  • Atunci când apelați apelurile de apel furnizate de utilizator cu date interne, trimiteți o vizualizare imuabilă sau o clonă, după caz, cu excepția cazului în care intenționați ca apelul să modifice datele, caz în care trebuie să îl validați după acest fapt.

Mesajul luați-home este să vă asigurați că niciun cod exterior nu poate să dețină un alias obiectelor care pot fi mutați pe care le utilizați intern, pentru a vă putea menține invarianții.

0
adăugat

Întotdeauna lucrez pentru a preveni lucruri precum atacurile prin injecție. Cu toate acestea, atunci când lucrați pe un site intranet intern, majoritatea caracteristicilor de securitate se simt ca un efort pierdut. Încă le fac, poate că nu prea bine.

0
adăugat

Ei bine, există un anumit set de bune practici pentru securitate. La minimum, pentru aplicațiile bazei de date, trebuie să aveți grijă de SQL Injection.

Alte chestii, cum ar fi parolele de hash, șirurile de criptare de conectare etc., sunt, de asemenea, standarde.

De aici, depinde de aplicația reală.

Din fericire, dacă lucrați cu cadre precum .Net, o mulțime de protecție a securității vine în construcție.

0
adăugat

Folosind Test Driven Development cu siguranță ajută. Scrieți o singură componentă la un moment dat și apoi enumerați toate cazurile potențiale pentru intrări (prin teste) înainte de a scrie codul. Acest lucru vă asigură că ați acoperit toate bazele și că nu ați scris niciun cod cool pe care nimeni nu îl va folosi, dar ar putea să-l rupă.

Deși nu fac nimic formal, petrec ceva timp uitându-mă la fiecare clasă și asigurându-mă că:

  1. dacă se află într-o stare validă că aceștia rămân într-o stare valabilă
  2. nu există nicio modalitate de a le construi într-o stare nevalidă
  3. În circumstanțe excepționale, aceștia vor eșua cu cât mai plăcut posibil (frecvent este o curățare și aruncare)
0
adăugat

Trebuie să programați întotdeauna defensiv aș spune chiar și pentru aplicațiile interne, pur și simplu pentru că utilizatorii ar putea doar prin șansa de a scrie ceva care vă sparge aplicația. S-a dat probabil că nu trebuie să vă faceți griji că încercați să vă înșelăți din bani, dar totuși. Întotdeauna programați defensiv și presupuneți că aplicația va eșua.

0
adăugat

În linia mea de lucru, codul nostru trebuie să fie de cea mai bună calitate Deci, ne concentrăm pe două lucruri principale:

  1. Testare
  2. Cod de recenzii

Cei care aduc acasă banii.

0
adăugat

Depinde.

Dacă aș fi hacking cu adevărat ceva pentru uzul meu, atunci voi scrie cel mai bun cod pe care nu trebuie să mă gândesc. Să compilatorul să fie prietenul meu pentru avertismente etc., dar nu voi crea automat tipuri de dracu '.

Cu cât este mai probabil ca codul să fie folosit, chiar și ocazional, am îmbunătățit nivelul controalelor.

  • minimal magic numbers
  • better variable names
  • fully checked & defined array/string lengths
  • programming by contract assertions
  • null value checks
  • exceptions (depending upon context of the code)
  • basic explanatory comments
  • accessible usage documentation (if perl etc.)
0
adăugat

Îi recomand oamenilor să scrie codul care este fascist în mediul de dezvoltare și binevoitor în producție.

În timpul dezvoltării, doriți să prindeți datele / logica / codul rău cât mai curând posibil, pentru a evita ca problemele să treacă neobservate sau să ducă la probleme mai târzii în care cauza principală este greu de urmărit.

În producție se ocupă de probleme cât mai grațios posibil. Dacă ceva este într-adevăr o eroare care nu poate fi recuperată, atunci să o gestionați și să prezentați acea informație utilizatorului.

Ca exemplu aici este codul nostru pentru a normaliza un vector. Dacă îl hrăniți cu date proaste în dezvoltare, va țipa, în producție revine o valoare de siguranță.

inline const Vector3 Normalize( Vector3arg vec )
{
    const float len = Length(vec);
    ASSERTMSG(len > 0.0f "Invalid Normalization");
    return len == 0.0f ? vec : vec / len;
}
0
adăugat
Folosim o modalitate similară de a "mări" detectarea problemei pe codul vechi. Macro-ul este ușor de adăugat, singurul său efect fiind un mesaj de depanare în timp ce se testează. Aceasta nu este o soluție miracolă, dar este mai bună decât "întoarcerea FALSE"; nimeni nu verifică vreodată
adăugat autor paercebal, sursa

Sunt foarte mult de părere că o programare corectă va proteja împotriva acestor riscuri. Lucruri precum evitarea funcțiilor depreciate, care (cel puțin în bibliotecile Microsoft C ++) sunt în general depreciate din cauza vulnerabilităților de securitate și validând tot ceea ce traversează o limită externă.

Funcțiile care sunt solicitate numai din codul dvs. nu ar trebui să necesite validarea excesivă a parametrilor, deoarece controlați apelantul, adică nu există o limită externă. Funcțiile numite de codul altor persoane ar trebui să presupună că parametrii de intrare vor fi invalizi și / sau rău-intenționați la un moment dat.

Abordarea mea față de rezolvarea unor funcții expuse este pur și simplu să se stingă, cu un mesaj util, dacă este posibil. Dacă apelantul nu poate obține parametrii corect, atunci problema este în codul lor și ar trebui să o repare, nu tu. (Evident, ați furnizat documentația pentru funcția dvs., deoarece este expusă.)

Injecția de cod este o problemă numai dacă aplicația dvs. poate ridica utilizatorul curent. Dacă un proces poate injecta codul în aplicația dvs., atunci ar putea să scrie cu ușurință codul în memorie și să îl execute oricum. Fără a putea obține acces complet la injectarea codului de sistem atacurile sunt inutile. (De aceea, aplicațiile utilizate de administratori nu ar trebui să poată fi scrise de utilizatori mai mici.)

0
adăugat

Aș recomanda să fiu defensivă pentru datele care introduc o "componentă" sau cadru. Într-o "componentă" sau cadru trebuie să se creadă că datele sunt "corecte".

Gândiți-vă așa. Depinde de apelant să furnizeze parametrii corecți, altfel toate funcțiile și metodele trebuie să verifice fiecare parametru inerent. Dar dacă verificarea este efectuată numai pentru apelant, verificarea este necesară doar o singură dată. Deci, un parametru ar trebui să fie "corect" și astfel poate fi trecut la niveluri mai mici.

  1. Verificați întotdeauna datele de la surse externe, utilizatori etc.
  2. O "componentă" sau cadru ar trebui să verifice întotdeauna apelurile primite.

Dacă există o eroare și o valoare greșită este utilizată într-un apel. Ce este cu adevărat cel mai bun lucru? Unul are doar un indiciu că "datele" pe care programul lucrează sunt greșite și altele precum ASSERTS, dar altele doresc să utilizeze raportarea avansată a erorilor și posibila recuperare a erorilor. În orice caz, datele se dovedesc a fi defecte și în câteva cazuri este bine să continuăm să lucrăm la aceasta. (rețineți că este bine dacă serverele nu mor cel puțin)

O imagine trimisă de un satelit ar putea fi un caz pentru a încerca recuperarea avansată a erorilor pe ... o imagine descărcată de pe internet pentru a pune o pictogramă de eroare pentru ...

0
adăugat

Java, JAR-urile semnate și JAAS.

Java pentru a preveni depășirea tamponului și explozia de pointer / stivă.

Nu utilizați JNI. (Java Native Interface) vă expune la bibliotecile DLL / Shared.

JAR-urile semnate pentru a opri încărcarea de clasă fiind o problemă de securitate.

JAAS poate lăsa cererea dvs. să nu aibă încredere în nimeni, chiar în sine.

J2EE are (adesea limitat) suport integrat pentru securitatea bazată pe roluri.

Există unele cheltuieli pentru unele dintre acestea, dar găurile de securitate dispăreau.

0
adăugat

Similar cu abyx, în echipa pe care o am pe dezvoltatori întotdeauna folosesc testarea unității și recenzii de cod. În plus, am și scopul de a mă asigura că nu încorporez codul pe care oamenii îl pot folosi - am tendința de a scrie cod numai pentru setul de metode de bază necesare pentru ca obiectul să funcționeze așa cum a fost specificat. Am descoperit că încorporarea unor metode care nu pot fi folosite niciodată, dar care să ofere funcționalitate pot introduce în mod neintenționat o utilizare "în spate" sau neintenționată / neprevăzută în sistem.

Este mult mai ușor să te întorci mai târziu și să introduci metode, atribute și proprietăți pentru care sunt cerute față de anticiparea ceva care nu ar putea veni niciodată.

0
adăugat
Ceea ce descrieți este, de asemenea, cunoscut sub numele de YAGNI - en.wikipedia.org/wiki/YAGNI
adăugat autor abyx, sursa

Din experiența mea, folosirea pozitivă a programării defensive nu înseamnă neapărat că veți ajunge la îmbunătățirea calității codului. Nu mă înțelegeți greșit, trebuie să programați defensiv pentru a prinde tipurile de probleme pe care le întâmpină utilizatorii - utilizatorii nu le plac atunci când programul dvs. se blochează pe ele - dar este puțin probabil ca acest cod să fie mai ușor de întreținut, test, etc.

Cu câțiva ani în urmă, am făcut politica de a folosi afirmații la toate nivelurile software-ului nostru și acest lucru - împreună cu testarea unităților, recenzii de cod etc., plus suitele noastre existente - au avut un efect pozitiv semnificativ asupra calității codului nostru.

0
adăugat