Defensive Programming
Defensive Programming
Безпечне програмування це форма безпечного планування, призначена для тривалого функціонування частин програмного забезпечення, незважаючи на непередбачене використання зазначеного програмного забезпечення. це був вступний заголовок на англомовній вікіпедії, як мені вдалося його перекласти. За логікою швидше виходить, що безпечне програмування просто випливає з принципів безпечного планування і полягає в тому, що будь-яка частина нашого ПЗ повинна витримувати нестандартне використання цього ПЗ. У зв'язку з цим я вирішив описати тут цю статтю так, як зміг зрозуміти її сам (якщо я виявився в чомусь не правий - виправте мене). Цю ідею можна як зниження чи усунення перспективи закону Мерфи(закону підлості, якщо простіше). Методи безпечного програмування використовуються насамперед тоді, коли частина ПЗ може бути використана неправильно, спеціально або з необережності, що може призвести до катастрофічних ефектів.
Безпечне програмування підходить для покращення ПЗ та вихідного коду, з точки зору наступних факторів: — Загальна якість: — Скорочення числа помилок і багів у ПЗ(це само собою). — Створення зрозумілого вихідного коду — Вихідники мають бути зрозумілі і легкочитаемие, це плюсом під час перевірки програми(і навіть інших розробників, якщо такі з'являться, і навіть самого себе). — ПЗ повинно поводитися передбачувано, незважаючи на несподівані вступні дані або дії користувача
Захищене програмування:
У середовищі ІТ-фахівців безпечне програмування іноді називають захищеним програмуванням. За їхніми заявами, такий підхід мінімізує баги. Помилки в ПЗ - потенційна лазівка,використовувана зломщиками для впровадження коду (code injection), атаки системи (забороняють обслуговування або інші атаки).
Різниця між безпечним програмуванням та програмуванням, що зустрічається у звичайній практиці, полягає в деяких припущеннях, зроблених програмістом, що намагається обробити всі можливі стани помилки (error states). Виходить, що програміст не може припустити, що специфічний виклик функції або бібліотеки буде працювати, як належить, і як воно обробляється в коді. Наприклад:
Ця функція обвалиться, якщо змінна input буде довше 1000 символів. Більшість можуть не приймати цю проблему всерйоз, припускаючи, що ніякий користувач не заноситиме так багато даних в змінну. Програміст, що практикує методи безпечного програмування, не припуститься такої помилки, тому що, коли в додатку є відомий баг, закон підлості (або Мерфі, кому як більше подобається) говорить, що даний баг обов'язково зустрінеться при використанні. Цей специфічний баг демонструє вразливість, яка використовує переповнення буфера. А ось як можна вирішити цей приклад:
Нижче наведено деякі методи безпечного програмування: Повторне використання налаштованого (Інтелектуального(intelligent)) вихідного коду: Якщо існуючий код протестований і добре показав себе в роботі, то повторне використання може знизити ймовірність появи помилок (багів) при впровадженні.
Проблеми успадкування: Перед повторним використанням старого коду, бібліотек, API, конфігурацій і т. д. обов'язково необхідно перевірити, чи дійсно старі напрацювання можна використовувати повторно, або навпаки, вони можуть викликати ймовірність успадкування багів. Проблеми успадкування, це властиві старим конструкціямпроблеми, пов'язані з тим, як вони будуть працювати з поточними вимогами, особливо якщо ці конструкції не були розроблені та протестовані з урахуванням поточних вимог.
У багатьох програмних продуктів виникли проблеми з успадкуванням старого вихідного коду. Наприклад:
- Наслідуваний код не може бути розроблений відповідно до правил захисного програмування, і тому може бути гіршої якості, ніж заново розроблений код.
- Може виявитися, що код, що успадковується, був написаний і протестований в умовах, які в даний час вже не застосовні. Таким чином виходить, що попередні тести контролю якості вже не котируються (не є валідними)
- Спочатку код був розроблений для введення ASCII даних. Тепер для введення даних використовується UTF-8.
- Початковий код був скомпільований і протестований на 32-бітній архітектурі, але при компіляції на 64-бітній архітектурі можуть виникнути нові арифметичні проблеми (такі як недійсні наведення типів та інші)
- Якщо код, що успадковується, спочатку призначався для offline-машин(Комп'ютерів не підключених до ЛЗ), то може статися що код стає вразливим при підключенні до мережі.
Таким чином виходить, що зазвичай успадкований код написаний без урахування поточних проблем. Наприклад, вихідний код, написаний десь у 1990 роках, швидше за все буде схильний до багатьох уразливостей, оскільки в той час про більшість цих уразливостей не було відомо.
- BIND 9, був представлений Полом Віксі та Девідом Конрадом як «BINDv9 is complete rewrite(Повністю переписаний)», «Security was a key consideration in design(Безпека була ключовим фактором при проектуванні)», називаючи безпеку, надійність інові протоколи є ключовим завданням для переписування старих вихідників.
- Microsoft Windows постраждали від уразливості у метафайлах Windows та іншими експлойтами, пов'язаними з форматом WMF. Центр безпеки Microsoft описує WMF-функції як «приблизно в 1990 роках, була додана підтримка WMF… Це був інший час з погляду спрямованості на безпеку. (я б сказав „з точки зору забезпечення безпеки“, але сенс полягає трохи в іншому)… все було повністю перевірено», не були розроблені з урахуванням ініціатив безпеки Microsoft.
- Oracle бореться з проблемами спадщини, такими як старі вихідники написані без урахування проблем звернення SQL-ін'єкцій та розширення привілеїв. В результаті багато вразливостей, на які було виділено час для виправлень, були не повністю виправлені. Це викликало різку критику з боку експертів у галузі безпеки. Також додаткову критику викликало те, що установки за замовчуванням (переважно спадщина старих версій), не збігалися з їхніми власними рекомендаціями безпеки, деякі з яких важко змінити, оскільки багато додатків вимагають менш безпечного налаштування успадкування для правильного функціонування.
Безпечна обробка введення та виведення (input та output(фіг знає як воно правильно має звучати українською)):
- Безпечна обробка введення та виведення відноситься до безпечної методики програмування, призначеної для запобігання багам та їх використання.
- Обробка вступних даних:
- Обробник вступних даних — програма, сервер, або інша комп'ютерна система, що обробляє отримані від користувача, клієнта або комп'ютерної мережі вступні дані.
- Безпечна обробка вступних даних необхідна длязапобігання вразливості, пов'язані з ін'єкцією коду, обходу каталогів та інших.
Канонізація
- Зломщики легко винаходять нові види надання невірних даних. Наприклад, якщо під час перевірки запитаний файл не є "/etc/passwd" , зломщик може використовувати інший варіант цього імені файлу, наприклад "/etc/./passwd" .
- Щоб уникнути помилок через неканонічний введення, використовують канонізацію API.
Інші методи:
-
Одна з найпоширеніших проблем, це неперевірене використання структур незмінного розміру та функцій для даних динамічного розміру
Проектування за контрактом:
- Проектування за контрактом використовує попередні умови, постумови та інваріанти, щоб дані (і стан програми в цілому) були оброблені. Це дозволяє зробити код кращим, документувати його припущення, і робити його безпечним. Також, воно може включати перевірку аргументів функції або методів до виконання тіла функції. Повернення значення перед виходом (break/return/throw/error code) також є плюсом.
- Твердження:
- Всередині функції, ви можете перевірити, що ви не посилаєтеся на щось не валідне (наприклад NULL) і що довжина масиву валідна перед зверненням до елементів, особливо на всіх тимчасових/локальних екземплярах. Хорошою евристикою вважається недовіра до бібліотек, написаних не вами. Таким чином, перевіряйте все, що ви отримали від них, після кожного їхнього виклику. це часто допомагає у створенні маленької бібліотеки «стверджуючих» та"перевіряючих" функцій, що запускаються спільно з логером, таким чином ви можете трасувати свої шляхи і скоротити великі цикли налагодження. З появою аспектно-орієнтованого програмування багато стомлюючих аспектів безпечного програмування пом'якшуються.
Отже. Короткі висновки.
- Скільки не використовуй код повторно, рано чи пізно його доведеться переписати з нуля (читай замінити щось новіше).
- Обробляйте всі вступні дані, без цього нікуди, і допоможе не випасти в overflow.
- Спадкування старого коду - це звичайно добре, але краще написати свіжий код з урахуванням усіх вимог.
- Методи захищеного програмування найкраще використовувати завжди. Та й канонізацію теж ніхто не скасовував.
Загалом Defensive Programming звучить гордо, але на ділі виходить, що не так воно і круто, як звучить. Не варто вдаватися до невивчених прийомів, якщо ліньки в них розбиратися, особливо назва прийому звучить вражаюче.