„Najlepsze praktyki” to termin, który może wywołać ożywioną debatę, zwłaszcza dotyczącą bezpieczeństwa. Ogólnie rzecz biorąc, najlepsze praktyki, a szczególnie w odniesieniu do bezpieczeństwa, często padają ofiarą dogmatycznego, a czasem ślepego oddania bezsensownym praktykom, które mają niewiele wspólnego z bezpieczeństwem, a więcej z wiarą lub tradycją. Niezależnie od tego, najlepsze praktyki pomagają zapewnić zestaw wskazówek, które pomagają zapewnić strukturę. Ponadto najlepsze praktyki można dostosować, aby pomóc w zaspokojeniu potrzeb konkretnej sytuacji. Przykładem może być specjalna seria 800 publikacji National Institute of Standards and Technology (NIST). Seria ta zawiera najlepsze praktyki i zalecenia, które można dostosować lub zintegrować z innymi praktykami, aby pomóc w poprawie i wyeliminowaniu tradycji określonej praktyki, która może nie mają już uzasadniony użytek. Biorąc to pod uwagę, większość ogólnych podręczników bezpieczeństwa zawiera zalecenia dotyczące aspektów programowania związanych z bezpieczeństwem — patrz na przykład Stallings — które w rzeczywistości mają bardzo realną korzyść w tworzeniu bezpieczniejszego oprogramowania. Oprócz projektowania zabezpieczeń w systemie od samego początku, istnieją również oczywiste wskazówki, które pomogą w tworzeniu bezpiecznego oprogramowania:
* Narzucaj silną identyfikację i uwierzytelnianie (I&A) dla krytycznych i wrażliwych systemów oprócz I&A dostępnego z systemu operacyjnego; najlepiej użyć uwierzytelniania opartego na tokenie lub uwierzytelniania biometrycznego jako części fazy inicjowania aplikacji.
* Dokładnie udokumentuj swój kod, w tym za pomocą słowników danych dla pełnej definicji dopuszczalnych danych wejściowych i wyjściowych funkcji oraz dopuszczalnego zakresu i typu wartości dla wszystkich zmiennych.
* Podczas przechowywania wrażliwych używaj zmiennych lokalnych, a nie zmiennych globalnych
dane, które powinny być używane tylko w ramach określonej procedury (tj. użyj architektury stosu procesów, aby ograniczyć nieumyślny lub nieautoryzowany dostęp do danych w stosie).
* Ponownie zainicjuj tymczasowe przechowywanie natychmiast po ostatnim prawidłowym użyciu zmiennej, co utrudnia oczyszczanie złoczyńców.
* Ogranicz funkcjonalność w określonym module do tego, co jest wymagane dla określonej pracy (np. nie używaj tego samego modułu do funkcji nadzorczych i rutynowych funkcji wykonywanych przez personel biurowy).
* Zdefiniuj widoki danych w bazach danych, które są zgodne z wymaganiami funkcjonalnymi i ograniczają dostęp do danych wrażliwych (np. widok danych z bazy danych dokumentacji medycznej powinien wykluczać identyfikatory pacjentów, gdy pracownik działu finansowego korzysta z bazy danych do agregacji statystycznej).
* Używaj silnego szyfrowania (nie szyfrowania własnego), które ma standardowe w branży procedury do ochrony poufnych i krytycznych danych na dysku. Lokalnie opracowane, domowe szyfrowanie na ogół nie jest tak bezpieczne.
* Nie zezwalaj programistom na dostęp do produkcyjnych baz danych.
* Randomizuj lub w inny sposób maskuj dane wrażliwe podczas generowania podzbiorów testowych z danych produkcyjnych.
* Użyj monitorów pokrycia testów, aby zweryfikować, czy wszystkie sekcje kodu źródłowego są rzeczywiście wykonywane podczas testów zapewnienia jakości; zbadać funkcje kodu, który nigdy nie jest wykonywany.
* Zintegruj możliwość logowania ze wszystkimi aplikacjami w celu debugowania, odzyskiwania danych po awariach w trakcie transakcji oraz w celach bezpieczeństwa, takich jak analiza kryminalistyczna.
* Utwórz rekordy pliku dziennika, które zawierają kryptograficznie dźwiękowy kod uwierzytelniania wiadomości (MAC), który sam zawiera adres MAC poprzedniego rekordu jako dane wejściowe algorytmu; ta technika zapewnia, że sfałszowanie lub zmodyfikowanie pliku dziennika będzie trudniejsze dla złoczyńcy.
* Rejestruj wszystkie inicjacje procesów dla programu i rejestruj zakończenie procesu; zawierać pełne informacje o tym, kto załadował program lub moduł.
* Rejestruj wszystkie modyfikacje rekordów i opcjonalnie udostępniaj również rejestrowanie w celu odczytu.
* Użyj blokowania na poziomie rekordu, aby zapobiec przypadkowemu nadpisaniu danych w rekordach, do których uzyskuje się dostęp jednocześnie. Pamiętaj, aby odblokować sekwencję blokad w odwrotnej kolejności sekwencji blokad, aby zapobiec zakleszczeniu. (Tak więc, jeśli zablokujesz zasób A, B i C w tej kolejności, odblokuj C, następnie B, a następnie A.)
* Podpisz swój kod źródłowy za pomocą podpisów cyfrowych.
* Używaj sum kontrolnych w produkcyjnych plikach wykonywalnych, aby utrudnić ukrycie nieautoryzowanych modyfikacji.
Mike Gerdes, były menedżer w AtomicTangerine, przedstawił te sugestie w trakcie dyskusji:
* Poleć czytelnikom przyjęcie praktyki projektowania kodu w bardziej holistyczny sposób. Powszechną praktyką jest pisanie i testowanie procedur w sposób, który weryfikuje, jak kod przetwarza dane w zamierzony sposób. Aby uniknąć skutków złośliwego kodu i ataków z wprowadzaniem danych, programista musi również napisać kod, który zajmuje się tym, co nie powinno być przetwarzane. Bardziej kompletna metodologia projektowania obejmowałaby również testowanie wszystkich informacji przychodzących, aby zapewnić wykluczenie wszelkich danych, które nie spełniają wymagań dotyczących akceptowalnych danych. Ta metoda powinna być stosowana w aplikacjach o wysokim ryzyku i tych, które mają wyjątkowo żmudny cykl testowy, i wyeliminuje wiele powszechnie stosowanych obecnie metod ataku.
* Ustal kryteria określania poziomu wrażliwości informacji zawartych lub przetwarzanych przez aplikację i podprogramy.
* Jeśli nie są one jeszcze obecne, rozważ wdrożenie formalnych procedur kontrolnych w metodologii programowania oprogramowania, aby upewnić się, że wszystkie dane są przeglądane podczas procesów zapewniania jakości oraz są sklasyfikowane i obsługiwane odpowiednio do przypisanego poziomu.
* Zidentyfikuj i uwzględnij wszelkie obowiązkowe cechy systemu operacyjnego i bezpieczeństwa sieci dla systemu produkcyjnego w specyfikacjach oprogramowania. Oprócz dostarczenia zespołom programistycznym i QA pewnej definicji środowiska, w którym ma działać oprogramowanie, dając administratorowi i użytkownikom końcowym wyobrażenie o tym, jakie były Twoje oczekiwania podczas tworzenia kodu, może być niezwykle przydatne w określaniu, gdzie oprogramowanie może, lub nie może być używany.
* W stosownych przypadkach zweryfikuj podpisy cyfrowe procedur przetwarzających poufne dane, gdy kod jest ładowany do wykonania.
* Jeśli uwzględniasz sumy kontrolne plików wykonywalnych dla kodu produkcyjnego, dołącz procedury, które weryfikują sumy kontrolne przy każdym ponownym uruchomieniu systemu.
Zespół Carnegie-Mellon Software Engineering Institute Computer Emergency Response Team (CERT) zapewnia dobrą listę „Top 10 bezpiecznych praktyk kodowania”. Poniższa lista zawiera kilka dodatkowych elementów, które należy wziąć pod uwagę oprócz elementów wymienionych wcześniej:
* Sprawdź poprawność danych wejściowych ze źródeł danych. Właściwa walidacja danych wejściowych może wyeliminować wiele luk w zabezpieczeniach oprogramowania.
* Skompiluj kod przy użyciu najwyższego poziomu ostrzeżeń dostępnego dla kompilatora i wyeliminuj ostrzeżenia, modyfikując kod.
* Utwórz architekturę oprogramowania i zaprojektuj oprogramowanie w celu wdrożenia i egzekwowania zabezpieczeń. Carnegie-Mellon ma wstępnie ustalony standard programowania według języka, który można znaleźć na stronie www.cert.org/secure-coding/scstandards.html
* Pamiętaj o zasadzie K-I-S-S (Keep It Simple, Stupid). Złożone projekty zwiększają prawdopodobieństwo wystąpienia błędów lub luk w zabezpieczeniach oraz potrzebę zwiększenia złożoności mechanizmów bezpieczeństwa lub wynikających z nich środków łagodzących.
* Opieraj decyzje o dostępie na pozwoleniu, a nie na wykluczeniu, aby przestrzegać zasady najmniejszych uprawnień.
* Oczyszczanie danych wysyłanych do innych systemów, takich jak powłoki poleceń, relacyjne bazy danych i gotowe komponenty komercyjne (COTS).
* Przećwicz dogłębną obronę w aplikacji, tak aby jeśli jedna warstwa ochrony okazała się niewystarczająca, inna może zapobiec lub ograniczyć lukę w zabezpieczeniach przed przekształceniem się w lukę, którą można wykorzystać.
* Ustanowienie dobrych technik zapewniania jakości, aby skuteczniej identyfikować i eliminować luki w zabezpieczeniach.
* Opracuj i/lub zastosuj bezpieczny standard kodowania dla docelowego języka i platformy programistycznej.
* Zdefiniuj wymagania bezpieczeństwa na początku projektu.
* Myśl jak haker i korzystaj z modelowania zagrożeń, aby przewidywać zagrożenia, na jakie może być narażone oprogramowanie. Jeśli zastanowisz się, jak można go zaatakować, będziesz w stanie zapobiec atakowi, zanim się pojawi.