Що стосується запитів до бази даних, завжди намагайтеся використовувати підготовлені параметризовані запити. mysqli
І PDO
бібліотеки підтримують це. Це нескінченно безпечніше, ніж використання функцій втечі, таких як mysql_real_escape_string
.
Так, mysql_real_escape_string
це фактично лише функція втечі рядка. Це не чарівна куля. Все, що він буде робити - це уникнути небезпечних символів для того, щоб їх можна було безпечно використовувати в одній рядку запиту. Однак, якщо ви не заздалегідь очистите свої дані, ви будете вразливі до певних векторів нападу.
Уявіть собі наступний SQL:
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
Ви повинні мати можливість бачити, що це вразливо для експлуатації.
Уявіть, що id
параметр містив загальний вектор атаки:
1 OR 1=1
Там немає ризикованих знаків для кодування, тому він пройде прямо через фільтр, що протікає. Залишаючи нас:
SELECT fields FROM table WHERE id= 1 OR 1=1
Це прекрасний вектор ін'єкції SQL і дозволив би зловмиснику повернути всі рядки. Або
1 or is_admin=1 order by id limit 1
який виробляє
SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1
Що дозволяє зловмиснику повернути перші дані адміністратора в цьому абсолютно вигаданому прикладі.
Хоча ці функції корисні, їх потрібно використовувати обережно. Вам потрібно переконатися, що всі вхідні дані в певній мірі перевірені. У цьому випадку ми бачимо, що нас можна експлуатувати, оскільки ми не перевіряли, чи змінна, яку ми використовували як число, насправді була числовою. У PHP вам слід широко використовувати набір функцій, щоб перевірити, чи є входи цілими числами, плаваючими, буквено-цифровими і т. Д. Але коли мова заходить про SQL, то найбільше слідкуйте за значенням підготовленого оператора. Вищевказаний код був би безпечним, якби це був підготовлений вислів, оскільки функції бази даних знали б, що 1 OR 1=1
це не є дійсним літералом.
Що стосується htmlspecialchars()
. Це власне мінне поле.
У PHP існує справжня проблема в тому, що він має цілий вибір різноманітних функцій, пов'язаних з html, і не має чітких рекомендацій щодо того, які саме функції виконувати.
По-перше, якщо ви знаходитесь всередині тегу HTML, у вас виникають реальні проблеми. Подивись на
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
Ми вже всередині тегу HTML, тому нам не потрібно робити <або> робити щось небезпечне. Наш вектор нападу просто міг бутиjavascript:alert(document.cookie)
Тепер результат HTML виглядає так
<img src= "javascript:alert(document.cookie)" />
Атака проходить прямо.
Це стає гірше. Чому? тому що htmlspecialchars
(коли його називають таким чином) кодує лише подвійні лапки, а не одиничні. Так якби ми мали
echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
Тепер наш злий нападник може вводити цілком нові параметри
pic.png' onclick='location.href=xxx' onmouseover='...
дає нам
<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
У цих випадках чарівної кулі немає, потрібно просто санітувати вхід самостійно. Якщо ви спробуєте і відфільтруєте поганих персонажів, вам точно не вдасться. Скористайтеся білим підходом і пропустіть лише хороші символи. Подивіться на шпаргалку XSS для прикладів того, як можуть бути різноманітні вектори
Навіть якщо ви використовуєте htmlspecialchars($string)
теги HTML поза межами HTML, ви все ще вразливі до багатобайтових векторів атаки на комір.
Найефективнішим, яким ви можете бути, є використання комбінації mb_convert_encoding та htmlentity наступним чином.
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');
Навіть це залишає IE6 вразливим, через те, як він обробляє UTF. Однак ви можете перейти до більш обмеженого кодування, такого як ISO-8859-1, поки використання IE6 не припиниться.
Для більш поглибленого вивчення багатобайтових проблем див. Https://stackoverflow.com/a/12118602/1820