Для тих, хто хоч якось стосувався теми безпеки, знають, що захист інформації - це безперервний процес. Він повинен забезпечувати щодо інформації:
- доступність;
- цілісність;
- конфіденційність.
Мені в університеті втовкмачували це в голову протягом усіх п'яти років навчання =)
Цей процес може забезпечувати якийсь рівень захисту, але при цьому неможливо добитися 100% безпеки. Але наше завдання як програмістів - максимально убезпечити додаток від різного типу загроз.
Помилки при розробці
Загрози існують абсолютно різні, і, на жаль, не всі їх можна передбачити. Однак існують найбільш поширені помилки, що призводять до появи вразливостей в додатках. У цій статті ми розглянемо найпопулярніші типи помилок, а також способи боротьби з ними. Отже, поїхали.
Робота з базами даних - SQL-ін'єкції
Чому цей пункт перший? Та тому що це - найважливіше. У базі даних зберігаються всі дані про ваших користувачів, саме це цікаво вашим конкурентам і іншим лиходіям в першу чергу.
Давайте розглянемо приклад уразливого коду.
І наш запит до бази даних прийме наступний вигляд:
UNION дозволяє об'єднувати декілька запитів в один. У параметрі ми передали номер неіснуючої записи: -1 і перша частина запиту нам нічого не повернула. Потім, у другій частині запиту ми звернулися до таблиці users і висмикнули поля email і password. попросивши назвати їх у вибірці як name і text. Цей запит виконався, і ми отримали в результаті email користувача та його пароль на сторінці виведення новин.
Рішення - PDO
PDO дозволяє захиститися від SQL-ін'єкцій. дозволяючи підставляти коректні дані в потрібні місця. Це відбувається завдяки Біндінг переданих даних - ми задаємо певні підстановки в запиті, а потім передаємо потрібні для них значення. Код вийде таким:
Тут ми назвали підстановку: id і потім в методі execute передали для неї значення. Завжди використовуйте PDO і Біндінг значень, це не дозволить прокинути що-небудь небезпечне в ваш SQL-запит.
PHP-injection
Це прийом, що дозволяє зловмисникові виконати довільний код на сайті. Простий приклад: статті сайту є файли з текстом. Для їх відкриття використовується конструкція include. яка приймає в себе get-параметри.
Remote File Injection
Щоб подивитися статтю, що зберігається в файлі main. використовується такий URL:
І буде завантажений код з сайту, так як функція include дозволяє виконувати код з віддалених серверів.
Давайте також розглянемо код, який додає до імені файлу з параметрів яке-небудь розширення.
При цьому в PHP буде виконаний інклуд файлу:
Як бачимо, тут розширення перетворилося в query-параметр і буде просто проігноровано.
Local File Injection
Зрозуміло, такий код можна використовувати і для доступу до секретних файлів на самому сервері. Наприклад, просто вказавши шлях в параметрі.
І файл буде виведений в браузері зловмисника.
Якщо на початку підключається файлу є якийсь шлях, то може використовуватися тільки локальна ін'єкція.
При цьому можуть використовуватися тільки відносні шляхи.
Їх можуть як підбирати, так і дізнатися шлях до поточного скрипта при виникненні помилки (якщо на сервері включений показ помилок, що є великою помилкою). Наприклад, передавши в get-параметр якусь неіснуючу абракадабру, зловмисник отримає помилку, при цьому буде виведена інформація про фото, в якому сталася помилка. А саме його шлях. Використовуючи його можна вже припускати про приблизний розташуванні різних файлів.
Захист від PHP-ін'єкцій
Можна придумати купу різних фильтраций. Але я б порадив дотримуватися правила - не допускати попадання даних від користувача в include, require, eval.
Вихід - використовувати функцію htmlentities ()
Вона перетворює символи начебто відкривають дужок в спеціальні символи, які браузер відображає як ті ж дужки і не сприймає їх як теги.
Тобто в браузері відвідувач побачить просто текст:
Що ще варто знати про безпечну розробці
Крім самих типових вразливостей є ще деякі кращі практики, що дозволяють зробити код більш безпечним. Давайте їх розглянемо.
Валідація та санітація даних
Всі дані від користувачів, оброблювані вашим кодом, є потенційно небезпечними. Крім того, часто нам потрібно просто домогтися того, щоб дані надходили до нас і зберігалися в якомусь певному форматі. Таким чином ми можемо говорити про деяку передбачуваності роботи над ними. У цьому нам допоможуть валідація і санітація даних.
Що нам в цьому плані пропонує PHP
По-перше - це приведення типів. Все id, які передає користувач варто приводити до integer (і не тільки це, потрібно все приводити до потрібного типу).
По-друге - регулярні вирази. У PHP існує багато функцій для роботи з регулярними виразами. Працюють вони дуже швидко, так як бібліотеки для роботи з ними написані на C і робота з регулярки відбувається на дуже низькому рівні.
По-третє, є вбудована функція filter_var (). яка дозволяє як затверджувати, так і виробляти санітацію. Наприклад, щоб провалідіровать email, досить написати:
Однак замість цього часто в коді можна побачити регулярки на сотні символів. Не треба так, все вже зроблено за вас.
шифрування
В першу чергу, хочу сказати, що шифрування - це дуже складна тема, і потрібно розуміти, що швидше за все ви розумієте її дуже поверхово. Однак є спеціально навчені люди, які займаються даною темою, і можуть запропонувати кращі практики, яких варто дотримуватися. У даній статті ми поговоримо про хешування. Дана процедура має на увазі під собою одностороннє шифрування, після якого з отриманого значення неможливо відновити вихідне.
Даний прийом часто використовується для зберігання паролів. Робиться це для того, щоб не зберігати вихідні паролі користувачів. Так як багато користувачів використовують однакові паролі на різних сайтах, і якщо базу з одного сайту вкрадуть і побачать паролі у відкритому вигляді, то швидше за все ці ж логін і пароль підійдуть і до інших сайтів. Отже, як же це реалізується. Для перевірки пароля ми просто шифруємо введений в форму логіна пароль за тим же алгоритмом і порівнюємо значення. Якщо вони співпали - пароль вірний.
Довгий час для цього використовувався алгоритм MD5. Для створення такого хеша в php є вбудована функція md5 (). Ось приклад її використання.
В результаті хешування цим алгоритмом вийде шестнадцатібайтний код у шістнадцятковому представленні. Як ви розумієте, число всіх можливих хеш є кінцевим. Тому в результаті хешування двох різних значень може вийти однаковий хеш. Це називається колізією. Цим страждають всі хеш-функції. На жаль, світ недосконалий. Так ось повертаючись до алгоритму MD5 - зараз для нього існують так звані райдужні таблиці (rainbow tables), які дозволяють отримати значення (не обов'язково вихідного), яке після хешування буде збігатися зі значенням захешірованного вихідного значення. Таким чином, знаючи хеш, можна швидко отримати пароль, який дозволить увійти на сайт.
Потім придумали додавати сіль. Або, як ще виражаються, «солити хеші». Суть в тому, що до вихідного паролю додається якийсь текст. В результаті виходить інший хеш.
Коли користувач вводить пароль, ми також додаємо до його паролю цей рядок, хешіруем вийшло значення і потім порівнюємо вийшло значення зі значенням в БД.
Таким чином забезпечується захист від Rainbow Tables, так як ймовірність колізії зменшується за рахунок того, що в хешіруемом тексті обов'язково повинна збігтися сіль.
Складати для підсолених значень райдужні таблиці ніхто не буде, проте MD5 навіть з сіллю на сьогоднішній день досить швидко підбирається, особливо якщо це комусь дуже потрібно.
Отже, використання MD5 - це помилка. Це застарілий, небезпечний алгоритм. Яким, проте, багато хто продовжує користуватися.
Як же бути зі зберіганням паролів?
Зараз в PHP є спеціальні функції для хешування, які використовують сучасні алгоритми шифрування. Це функції _passwordhash () і _passwordverify (). Перша функція створює хеш для значення.
У другу передаються введений пароль і хеш, отриманий першою функцією. В результаті повернеться false або true. в залежності від того, чи правильний пароль.
У ці функції вже вбудована робота з сіллю, і вона автоматично додається в хеш при його створенні, і так же витягується з хеша при порівнянні його з введенням паролем. Використовуйте ці функції і буде вам щастя.
висновок
У цій статті я лише поверхово розповів про найбільш популярних помилки початківців розробників, а також навів приклади того, як потрібно з ними боротися. Зараз я б порадив вам вивчити кожне з цих напрямків більш детально, щоб розуміти, чого варто боятися в першу чергу. Гугл вам на допомогу.
Які ще бувають факапи в плані безпеки?
Зрозуміло, у всіх бувають факапи, всі ми люди. Нещодавно і у мене був - в файлі конфігурації проекту лежав пароль від пошти для відправки листів по imap. Забув заборонити цей конфігураційний файл в .gitignore. як результат - пароль виявився у відкритому доступі на github. На щастя, знайшлася людина, яка написала мені про цю помилку. Пароль я тут же поміняв, а людини віддячив невеликим матеріальним бонусом. Зрозуміло, мені дуже пощастило. Адже маючи доступ до пошти, можна було отримати доступ до відправленим листам і злити базу користувачів. Або, що ще гірше, розіслати їм з цієї пошти якусь гидоту.
Рішення в даному випадку наступне - ігнор всі конфіги в .gitignore відразу при їх створенні, а краще взагалі виносити їх за межі сховища.