Warning: Missing argument 2 for wpdb::prepare(), called in /home/stromber/public_html/kryptoblog/wp-content/plugins/wp-super-edit/wp-super-edit.core.class.php on line 109 and defined in /home/stromber/public_html/kryptoblog/wp-includes/wp-db.php on line 1222
Koda säkrare med CERT » Kryptoblog

Koda säkrare med CERT

January 22nd, 2008 by Joachim Strömbergson Leave a reply »

CERT har ett pågående projekt för att utveckla kodningsregler och rekommendationer för att skriva säkrare program i C och C++. Reglerna utvecklas som ett öppet projekt och utvecklingen sker på projektets webbplats.

Här hittar du reglerna för C-kod och här hittar du reglerna för C++-kod.

Reglerna tar upp ett stort antal aspekter, vilket en snabb lista med kategorierna för C-kod visar:


01. Preprocessor (PRE)

02. Declarations and Initialization (DCL)

03. Expressions (EXP)

04. Integers (INT)

05. Floating Point (FLP)

06. Arrays (ARR)

07. Characters and Strings (STR)

08. Memory Management (MEM)

09. Input Output (FIO)

10. Temporary Files (TMP)

11. Environment (ENV)

12. Signals (SIG)

13. Error Handling (ERR)

14. Miscellaneous (MSC)

50. POSIX (POS)

99. The Void

Under de olika kategorierna kommer sedan ett antal regler som alla följer en gemensam form med beskrivning exempel, analys av säkerhetsproblem och referenser. Ett exemåel är INT07-A. Only use signed or unsigned char type for numeric values:


The three types char, signed char, and unsigned char are collectively called the character types. Compilers have the latitude to define char to have the same range, representation, and behavior as either signed char or unsigned char. Irrespective of the choice made, char is a separate type from the other two and is not compatible with either.

Only use signed char and unsigned char types for the storage and use of numeric values, as this is the only way to (portably) guarantee the signedness of the character types.
Non-Compliant Code Example

In this non-compliant code example, the char-type variable c may be signed or unsigned. Assuming 8-bit, two’s complement character types, this code may either print out i/c = 5 (unsigned) or i/c = -17 (signed). As a result, it is much more difficult to reason about the correctness of a program without knowing if these integers are signed or unsigned.

char c = 200;
int i = 1000;
printf(“i/c = %dn”, i/c);

Compliant Solution
In this compliant solution, the variable c is declared as unsigned char. The subsequent division operation is now independent of the signedness of char and consequently has a predictable result.

unsigned char c = 200;
int i = 1000;
printf(“i/c = %dn”, i/c);

Risk Assessment
This is a subtle error that results in a disturbingly broad range of potentially severe vulnerabilities.
Recommendation Severity Likelihood Remediation Cost Priority Level
INT07-A 2 (medium) 2 (probable) 2 (medium) P8 L2

Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References
[ISO/IEC 9899-1999] Section 6.2.5, “Types”
[MISRA 04] Rule 6.2, “Signed and unsigned char type shall be used only for the storage and use of numeric values”

Det finns även en bok från CERT på området av Robert C. Seacord:
Boken

För den som har bråttom har CERT även en lista på de tio viktigaste generella reglerna, regler som inte bara går att applicera på C och C++:


1. Validate input. Validate input from all untrusted data sources. Proper input validation can eliminate the vast majority of software vulnerabilities. Be suspicious of most external data sources, including command line arguments, network interfaces, environmental variables, and user controlled files [Seacord 05].

2. Heed compiler warnings. Compile code using the highest warning level available for your compiler and eliminate warnings by modifying the code [C MSC00-A, C++ MSC00-A].

3. Architect and design for security policies. Create a software architecture and design your software to implement and enforce security policies. For example, if your system requires different privileges at different times, consider dividing the system into distinct intercommunicating subsystems, each with an appropriate privilege set.

4. Keep it simple. Keep the design as simple and small as possible [Saltzer 74, Saltzer 75]. Complex designs increase the likelihood that errors will be made in their implementation, configuration, and use. Additionally, the effort required to achieve an appropriate level of assurance increases dramatically as security mechanisms become more complex.

5. Default deny. Base access decisions on permission rather than exclusion. This means that, by default, access is denied and the protection scheme identifies conditions under which access is permitted [Saltzer 74, Saltzer 75].

6. Adhere to the principle of least privilege. Every process should execute with the the least set of privileges necessary to complete the job. Any elevated permission should be held for a minimum time. This approach reduces the opportunities an attacker has to execute arbitrary code with elevated privileges [Saltzer 74, Saltzer 75].

7. Sanitize data sent to other systems. Sanitize all data passed to complex subsystems [C STR02-A] such as command shells, relational databases, and commercial off-the-shelf (COTS) components. Attackers may be able to invoke unused functionality in these components through the use of SQL, command, or other injection attacks. This is not necessarily an input validation problem because the complex subsystem being invoked does not understand the context in which the call is made. Because the calling process understands the context, it is responsible for sanitizing the data before invoking the subsystem.

8. Practice defense in depth. Manage risk with multiple defensive strategies, so that if one layer of defense turns out to be inadequate, another layer of defense can prevent a security flaw from becoming an exploitable vulnerability and/or limit the consequences of a successful exploit. For example, combining secure programming techniques with secure runtime environments should reduce the likelihood that vulnerabilities remaining in the code at deployment time can be exploited in the operational environment [Seacord 05].

9. Use effective quality assurance techniques. Good quality assurance techniques can be effective in identifying and eliminating vulnerabilities. Penetration testing, fuzz testing, and source code audits should all be incorporated as part of an effective quality assurance program. Independent security reviews can lead to more secure systems. External reviewers bring an independent perspective; for example, in identifying and correcting invalid assumptions [Seacord 05].

10. Adopt a secure coding standard. Develop and/or apply a secure coding standard for your target development language and platform.

Nu gäller det bara att till sig allt och börja applicera det också...

No related posts.

Related posts brought to you by Yet Another Related Posts Plugin.

Advertisement

9 comments

  1. Björn Persson says:

    Skriva säkra program i C? En sådan självmotsägelse! Om man menar allvar med att skriva säkra program så är det första man gör att spola C. Farliga programmeringsspråk ger farliga program. Om man inte kan något lämpligare språk så kan man lära sig. Att komma igång i ett nytt språk är ingen stor sak för en kompetent programmerare.

    Det finns ett programmeringsspråk som är konstruerat från grunden för att hjälpa programmeraren att göra koden så pålitlig som möjligt. Det konstruerades i slutet av 1970-talet, standardiserades första gången 1980, och blev ISO-standard 1983. Den senaste förbättringen färdigställdes 2005 och blev formellt ISO-standard 2007. Det är ett statiskt typat språk med ett typsystem som varken C eller C++ kommer i närheten av. Man kan definiera sina egna heltals- och flyttalstyper och precis vilka värden de ska kunna ha, och man får gränskontroll på såväl skalärer och uppräknade typer som vektorer, vilket gör stränghanteringen mycket behändig utan risk för buffertspill eller formatsträngsbuggar. Givetvis finns också arv, polymorfi och överlagring, allt som behövs för objektorienterad programmering.

    Multitrådning finns inbyggt i språket, vilket gör att kompilatorn kan hjälpa till på ett helt annat sätt än när trådning läggs på som ett bibliotek. För det mesta programmerar man på en ganska hög nivå, men man kan också styra detaljer på en mycket låg nivå när man verkligen behöver. Man kan också gå förbi säkerhetsspärrarna när det är nödvändigt. Det går alldeles utmärkt att skjuta sig i foten – men först efter att man uttryckligen har talat om för kompilatorn att man faktiskt vill använda sin fot som måltavla.

    Allt detta gör att misstag som skulle ha blivit säkerhetshål eller obegripliga krascher i ett C-program i stället upptäcks vid kompileringen och genast rättas till. Priset är att det tar litet längre tid att kompilera än C, eftersom kompilatorn gör så mycket mer. Eftersom språket kompileras till maskinkod så får man prestanda fullt jämförbara med vad andra kompilerade språk ger. Och ja, det finns en fri kompilator. Den heter GCC.

    Någon som vill försöka gissa vad språket heter?

  2. Joachim says:

    Aloha!

    Björn: Först, du noterade att jag skrev “säkra(re)”?

    Sedan har du rätt i att det finns språk där mycket av problematiken med C och C++ inte ens finns. Ada, vilket jag tror du syftar på är ett sådant språk. Andra språk som inte alls kommer med samma uppsättning vårtor är språk som Erlang, Eiffel, Oberon etc. Även Java har ett flertal mekanismer som gör dess kod säkrare och minskar risken för fel.

    MEN Det hjälper inte. Kodbasen som i dag finns i C, C++ samt antalet SW-utvecklare som kodar i C och C++ är så stor att det för många inte går att byta språk. Att då istället introducera kodningsregler, implementera granskningar med ex lclint, coverity, köra med fuzzing och metodik för att göra sin kod SÄKRARE tycker jag är ett bra sätt att arbeta. Att få in säkerhetstänkande i metodik och utvecklingsprocessen.

    Sedan kan man hoppas på att världen rör sig mot språk som är bättre lämpade. Inte minst problemet med multitrådning och parallell programmering för att utnyttja multicores öppnar ju upp en hel lastpall med maskburkar.

    Att koda säkert i C och C++ är svårt, att koda multitrådat säkert i C och C++, det är mycket värre.

  3. Blaufish says:

    Ada vs C/C++ diskussionen har sina meriter, det stämmer att det idag är nästan direkt olämpligt att påbörja nya program i C/C++ då Java och .NET som nu är kommersiellt gångbara erbjuder många värdefulla egenskaper (minnesskydd m.m.).

    Däremot är ju åtminstone 9 av 10 regler boken föreslår direkt tillämpbara på ALL programmering, oberoende av programmeringsspråk. Och om någon tror att Ada/C#/Java löser alla problem, ja då bör man snarast läsa in sig på bl.a. Injection attacker, XSS/CSRF/JsHijacking/... attacker, directory traversal. Glöm dessutom inte alla applikationsspecifika problem, de som är helt unika och skapade av programmerna, de som bara finns i detta program. Problemen idag är snarare att utvecklarna gör bort sig på nivåerna ovanför, än att man har problem med B.O… Att diskutera säkerhet utifrån B.O. känns väldigt mycket som gammalt 1990-tal.

    Problemet är precis som Jochim säger – att få in säkerhet i metodik, utveckling och personalutbildning. Visst gör Ada/C#/Java att man slipper en viss delmängd av problematiken, men det grundläggande problemet – utvecklarnas kunskaper och den tid de kan lägga på att arbeta med säkerhet, det löser inget programspråk.

    Speciellt fel med “lita (blint) på programspråket / verktyget” filosofin är att man helt missar allt som inte täcks upp av detta, och man har ingen som helst chans att hitta de applikationsspecifika problem som inget automatiskt verktyg i hela världen kan hitta.

    Att säkerhet kräver enormt mycket av de som utvecklar kommer man aldrig ifrån. Det finns ingen enkel lösning, varken på en eller tre bokstäver.

  4. Björn Persson says:

    Joachim:
    “Björn: Först, du noterade att jag skrev “säkra(re)”?”
    Om du helt enkelt hade skrivit “säkrare” så skulle du ha haft en poäng där (även om jag tycker att “mindre farliga” vore en bättre formulering). Parenteserna runt “re” uppfattar jag som att man ska läsa både “säkra” och “säkrare”, och för övrigt står det “säkert” i rubriken.

    “Även Java har ett flertal mekanismer som gör dess kod säkrare och minskar risken för fel.”
    Det är sant. Man slipper åtminstone buffertspill. Den allra största defekten i C har dock javas konstruktörer omsorgsfullt kopierat: if(a=b).

    “Kodbasen som i dag finns i C, C++ samt antalet SW-utvecklare som kodar i C och C++ är så stor att det för många inte går att byta språk.”
    Jag menar inte att alla ska sätta sig och översätta all sin befintliga C-kod till ada. Först och främst vill jag att folk ska sluta välja C när de startar nya projekt. Argumentet att det finns många utvecklare som kodar i C och C++ förstår jag inte. Det är ju just de som behöver övertalas att välja ett säkrare språk till nästa projekt.

    “Att få in säkerhetstänkande i metodik och utvecklingsprocessen.”
    Det är jag helt med på, men valet av språk är en viktig del av säkerhetstänkandet.

    “Sedan kan man hoppas på att världen rör sig mot språk som är bättre lämpade.”
    Jag nöjer mig inte med att hoppas. Jag försöker driva på. Därför tar jag vara på sådana här tillfällen att påpeka att det finns välkonstruerade språk och illa konstruerade språk.

    Blaufish:
    Jag har inte försökt påstå att ada löser alla problem i världen. Joachim skrev en artikel om att koda säkert i C och C++, och jag påpekade att kodar säkert gör man bättre i andra språk. Det stämmer att de tio reglerna är allmängiltiga, men Joachims artikel är likafullt inriktad på C och C++, och därför tyckte jag att språkaspekten behövde belysas.

  5. Joachim says:

    Aloha!

    Björn: Rubriken ändrad och paranteser borttagna. Du har rätt i att folk behöver uppmärksammas på att det finns andra språk. Vidare har du rätt i att det inte räcker med att hoppas på att trenden skall gå mot säkrare språk.

    Men jag tror tyvärr att vi kommer att se stor användning av C och C++ i många, många år framöver. Vi pratar inte om att byta språk i nästa projekt eller ens nästnästa. Detta då även dessa språk med stor sannolikhet bygger på tidigare kodbas.

    Metodik och processer för att skrivare allt säkrar kod. Användning av bibliotek som hjälper till att lösa problem och verktyg för att analysera koden och inte minst verktyg för att hjälpa till att migrera kodbasen tror jag på.

    Är det någon som tittat på Intels Threading Building Blocks? Ger det ett bra stöd för att skriva multitrådat utan att automatiskt skjuta sig själv i foten från fler håll samtidigt?

    Intel TBB:
    http://www.intel.com/cd/software/products/asmo-na/eng/294797.htm

  6. Chol says:

    Tjing!

    Som gammal Ada-utvecklare kan jag inte annat än att hålla med. Sällan man hade några slarvfel som slank igenom kompilatorn utan de fel man fick var mer av karakären logiska fel. Alltså sådana som det skulle behövas en kompilator som klarat Turing-testet och lite till för att upptäcka… Extra trevligt är ju såklart det inte trådstödet som gör synkronisering mellan trådar till en barnlek. Visst är man fortfarande tvungen att säkra data via protected objects eller dylikt men det är hursomhelst mycket enklare och säkrare när det finns inbyggt i språket. Och det var Ada95. Ada2005 tar ju saker och ting ytterligare ett steg framåt!

    Synd bara att Ada är relativt ovanligt att se i kompilatorer för DSP:er och inbyggda system. Antar att det är enklare att skriva en högoptimerande kompilator för ett enklare språk som C än för t ex Ada.

    Extreme Programming, Test Driven Development och Keep It Simple Stupid fungerade alldeles utmärkt ihop med Ada 95 och aUnit för enhetstester och drog ner antalet fel ytterligare. Kräver dock dedikerade programmerare med någorlunda samma attityd till kodningen…
    Så visst är processer viktigt!

    Ett annat generellt problem är i min mening att man drar objektorienting lite för långt. Jag tycker om att modellera objektorienterat men när man väl skall implementera så håller jag det så funktionellt som möjligt. Att låta hundratals objekt ha sin egna tillstånd och sidoeffekter åt både höger, vänster, uppåt och neråt är att be om problem.
    Skriver man funktionellt så kan man ju utan större problem matematiskt bevisa att koden uppfyller sina specifikationer.

    Om man använder .NET eller Mono så har ju MS släppt en beta för F# i höstas. Tankade ner det och testade lite i julas och det var en inte helt oangenäm upplevelse. Ett funktionellt programspråk i skrivbordsmiljö. Trodde man inte när man fick sina första religiösa upplevelser i ML i början av 90-talet! 😉
    F#: http://research.microsoft.com/fsharp/fsharp.aspx

    Inte testat TBB men ett intressant initiativ! Är dock ganska säker på att jag skulle klara av att skjuta mig i foten ändå...;-)

Leave a Reply

You must be logged in to post a comment.