Які найкращі функції санітації входу для PHP?


161

Я намагаюся придумати функцію, через яку я можу пропустити всі свої струни для оздоровлення. Так що рядок, яка виходить з неї, буде безпечною для вставки бази даних. Але є так багато функцій фільтрації там, я не впевнений, які з них я повинен використовувати / потребувати.

Будь ласка, допоможіть мені заповнити бланки:

function filterThis($string) {
    $string = mysql_real_escape_string($string);
    $string = htmlentities($string);
    etc...
    return $string;
}

4
для вставки, це добре просто захистити від ін'єкції SQL, використовуючи mysql_real_escape_string. Саме тоді, коли ви використовуєте виделені дані (у форматі html або у формулі / функції php), вам слід застосувати htmlentities
davidosomething

Дивіться stackoverflow.com/questions/60174/… відповідь, характерну для очищення для вставки в базу даних (вона дає приклад PDO, про який інші згадували нижче).
Пат

Відповіді:


433

стій!

Ви тут помиляєтесь. О, ні, ви вибрали правильні функції PHP, щоб зробити ваші дані трохи безпечнішими. Добре. Ваша помилка - в порядку операцій , а також як і де використовувати ці функції.

Важливо зрозуміти різницю між санітизацією та валідацією даних користувачів, вилученням даних для зберігання та видачею даних для презентації.

Санітація та перевірка даних користувачів

Коли користувачі подають дані, вам потрібно переконатися, що вони надали те, що ви очікуєте.

Санітація та фільтрування

Наприклад, якщо ви очікуєте номер, переконайтеся, що подані дані є числом . Ви також можете передавати дані користувачів іншим типам. Все подане спочатку трактується як рядок, тому примушення відомого числових даних перетворюватися на ціле число або плавець робить санітарію швидкою і безболісною.

Що з текстовими полями та текстовими областями у вільній формі? Вам потрібно переконатися, що в цих полях немає нічого несподіваного. Головним чином, ви повинні переконатися, що поля, які не мають вмісту HTML, насправді не містять HTML. Є два способи вирішити цю проблему.

По-перше, ви можете спробувати уникнути введення HTML за допомогою htmlspecialchars. Не слід використовувати htmlentitiesдля нейтралізації HTML, оскільки він також виконуватиме кодування акцентованих та інших символів, які, на його думку, також потребують кодування.

По-друге, ви можете спробувати видалити будь-який можливий HTML. strip_tagsшвидко і легко, але також неохайно. HTML очищувач виконує набагато більш ретельну роботу, як знімати весь HTML, так і дозволяючи вибірковий білий список тегів та атрибутів.

Сучасні версії PHP поставляються з розширенням фільтра , що забезпечує всебічний спосіб очищення введення користувача.

Перевірка

Переконатися, що подані дані не містять несподіваного вмісту - це лише половина роботи. Вам також потрібно спробувати переконатися, що подані дані містять значення, з якими ви можете реально працювати.

Якщо ви очікуєте числа від 1 до 10, вам потрібно перевірити це значення. Якщо ви використовуєте один з цих нових фантазійних числових входів епохи HTML5 із спінером та кроками, переконайтесь, що подані дані відповідають кроку.

Якщо ці дані надходили зі спадного меню, переконайтеся, що подане значення є таким, яке з’явилося в меню.

Що з текстовими вводами, які відповідають іншим потребам? Наприклад, дати введення повинні бути перевірені через strtotimeабо клас DateTime . Дана дата повинна бути між очікуваними діапазонами. Що з адресами електронної пошти? Раніше згадане розширення фільтра може перевірити, чи адреса добре сформована, хоча я фанат бібліотеки is_email .

Те саме стосується всіх інших елементів управління. У вас є кнопки радіо? Підтвердити список. У вас є прапорці? Підтвердити список. Завантажити файл? Переконайтеся, що файл очікуваного типу, і обробіть ім’я файлу як нефільтровані дані користувача.

Кожен сучасний веб-переглядач оснащений повним набором інструментів для розробників, вбудованих прямо, завдяки чому кожен може маніпулювати вашою формою. Ваш код повинен припускати, що користувач повністю зняв усі обмеження щодо вмісту форми на стороні клієнта !

Уникнення даних для зберігання

Тепер, коли ви переконалися, що ваші дані є у очікуваному форматі та містять лише очікувані значення, вам потрібно потурбуватися про збереження цих даних для зберігання.

Кожен окремий механізм зберігання даних має певний спосіб переконатися, що дані належним чином виконуються та кодуються. Якщо ви будуєте SQL, то прийнятим способом передачі даних у запитах є підготовка заяв із заповненнями .

Одним з кращих способів роботи з більшістю баз даних SQL в PHP є розширення PDO . З цього випливає загальна схема підготовки оператора , прив'язування змінних до оператора , потім відправлення оператора та змінних на сервер . Якщо ви раніше не працювали з PDO, ось непоганий навчальний посібник, орієнтований на MySQL .

Деякі бази даних SQL мають власні розширення спеціальностей у PHP, включаючи SQL Server , PostgreSQL та SQLite 3 . Кожне з цих розширень підготувало підтримку операторів, яка працює так само, як і PDO. Іноді вам може знадобитися використовувати ці розширення замість PDO для підтримки нестандартних функцій чи поведінки.

MySQL також має власні розширення PHP. Два з них, насправді. Ви хочете коли-небудь використовувати той, який називається mysqli . Старе розширення "mysql" було застарілим і не є безпечним або розумним для використання в сучасну епоху.

Я особисто не шанувальник mysqli. Те, як воно виконує змінну прив'язку підготовлених висловлювань, є негнучким і може бути болючим у використанні. Якщо ви сумніваєтесь, замість цього використовуйте PDO.

Якщо ви не використовуєте базу даних SQL для зберігання даних, перегляньте документацію інтерфейсу бази даних, який ви використовуєте, щоб визначити, як безпечно передавати дані через них.

Коли це можливо, переконайтеся, що ваша база даних зберігає ваші дані у відповідному форматі. Зберігати номери в числових полях. Зберігати дати в полях дат. Зберігайте гроші в десятковому полі, а не в полі з плаваючою комою. Перегляньте документацію, надану вашою базою даних щодо правильного зберігання різних типів даних.

Дані для виходу з презентації

Кожен раз, коли ви показуєте дані користувачам, ви повинні переконатися, що дані надійно захищені, якщо ви не знаєте, що їх не слід уникати.

Випромінюючи HTML, ви майже завжди повинні передавати будь-які дані, які були спочатку надані користувачем htmlspecialchars. Насправді, єдиний раз, коли ви цього не повинні робити, це коли ви знаєте, що користувач надав HTML, і знаєте, що це вже було дезінфіковано за допомогою білого списку.

Іноді вам потрібно створити трохи Javascript за допомогою PHP. У Javascript немає таких самих правил, що і у HTML! Безпечний спосіб надати користувачеві значення Javascript через PHP json_encode.

І більше

Існує ще багато нюансів перевірки даних.

Наприклад, кодування набору символів може бути величезною пасткою . Ваша заявка повинна слідувати практиці, викладеній у " UTF-8, до кінця ". Існують гіпотетичні атаки, які можуть виникати, коли ви розглядаєте рядкові дані як неправильний набір символів.

Раніше я згадав інструменти для налагодження браузера. Ці інструменти також можуть використовуватися для маніпулювання даними cookie. Файли cookie слід розглядати як ненадійне введення користувача .

Перевірка даних та її вихід - лише один із аспектів безпеки веб-додатків. Ви повинні ознайомитись з методологіями атаки веб-додатків, щоб ви могли створити захист проти них.


І вказуючи його, будьте впевнені, що він у списку підтримуваних кодувань.
Чарльз

3
І взагалі не використовуйте htmlentities, замініть його на htmlspecialchars з метою заміни справедливого <>, а не кожного символу на його сутність
Ваше загальне чуття

6
Просто не забудьте дзвонити htmlspecialcharsдвічі, оскільки він говорить про це у частині "Коли користувачі надсилають частину даних" та у частині "Під час відображення даних".
Савагеман

2
Отримано. Найкорисніша відповідь, яку я прочитав з багатьох питань і запитань щодо ін'єкції SQL.
акінурі

Абсолютно якісна відповідь з багатьма поясненнями та посиланнями для майбутніх користувачів, щоб вивчити більше варіантів. Отримав і мене вгору ...
Джеймс Уокер

32

Найбільш ефективна санітарія для запобігання ін'єкції SQL - це параметризація з використанням PDO. Використовуючи параметризовані запити, запит відокремлюється від даних, щоб усунути загрозу введення SQL першого порядку.

Що стосується видалення HTML, strip_tagsце, мабуть, найкраща ідея для видалення HTML, оскільки він просто видалить усе. htmlentitiesробить те, що це звучить, так що це теж працює. Якщо вам потрібно розібрати, який HTML дозволити (тобто ви хочете дозволити деякі теги), вам слід використовувати зрілий існуючий аналізатор, такий як очищувач HTML


2
Боже, я написав цю гігантську стінку тексту лише тому, що я не бачив, щоб хтось згадував HTML очищувач, і ось ти побив мене, як 40 хвилин. ;)
Чарльз

3
Чи не слід виводити лише HTML на виході? IMO ви ніколи не повинні змінювати вхідні дані - ви ніколи не знаєте, коли вам це знадобиться
Джо Філіпс,

11

Введення бази даних - Як запобігти введенню SQL

  1. Переконайтеся, що дані типу цілого числа, наприклад, є дійсними, переконавшись, що вони фактично є цілим числом
    • Що стосується не рядків, вам потрібно переконатися, що дані насправді є правильним типом
    • Що стосується рядків, вам потрібно переконатися, що рядок оточений лапками в запиті (очевидно, інакше він би навіть не працював)
  2. Введіть значення в базу даних, уникаючи введення SQL (mysql_real_escape_string або параметризованих запитів)
  3. Отримуючи значення з бази даних, не забудьте уникнути атак з перехресними сценаріями, переконавшись, що HTML не може бути введений на сторінку (htmlspecialchars)

Перш ніж вставляти або оновлювати його в базу даних, потрібно уникати введення користувача. Ось більш старий спосіб зробити це. Ви хочете використовувати параметризовані запити зараз (можливо, з класу PDO).

$mysql['username'] = mysql_real_escape_string($clean['username']);
$sql = "SELECT * FROM userlist WHERE username = '{$mysql['username']}'";
$result = mysql_query($sql);

Виведення з бази даних - Як запобігти XSS (міжсайтовий сценарій)

Використовувати htmlspecialchars()лише під час виведення даних із бази даних. Те саме стосується і очищувача HTML. Приклад:

$html['username'] = htmlspecialchars($clean['username'])

І нарешті ... те, що ви просили

Треба зазначити, що якщо ви використовуєте об'єкти PDO з параметризованими запитами (правильний спосіб зробити це), то насправді не існує простого способу цього легко досягти. Але якщо ви використовуєте старий спосіб mysql, то це саме те, що вам потрібно.

function filterThis($string) {
    return mysql_real_escape_string($string);
}

5

Мої 5 копійок.

Тут ніхто не розуміє, як mysql_real_escape_stringпрацює. Ця функція нічого не фільтрує і не санірує.
Отже, ви не можете використовувати цю функцію як універсальний фільтр, який позбавить вас від ін'єкцій.
Ви можете використовувати його лише тоді, коли зрозумієте, як у творах і де це застосовано.

У мене є відповідь на дуже подібне питання, про яке я вже писав: У PHP під час надсилання рядків до бази даних я повинен дбати про незаконні символи за допомогою htmlspecialchars () або використовувати регулярний вираз?
Будь ласка, натисніть для повного пояснення щодо безпеки на базі даних.

Що стосується важливих особливостей - Чарльз має рацію розділити ці функції.
Уявіть собі, що ви збираєтеся вставити дані, згенеровані адміністратором, якому дозволено публікувати HTML. ваша функція це зіпсує.

Хоча я б радив проти химерностей. Ця функція застаріла давно. Якщо ви хочете замінити тільки <, >і "символи в цілях безпеки HTML - використовувати функцію , яка була розроблена спеціально для цієї мети - An htmlspecialchars () один.


1
mysql_real_escape_stringуникає потрібних символів всередині рядка. Це не суто фільтрування чи санітарія, але вкладати рядок у лапки також немає (і всі це роблять, я майже ніколи не бачив питання про це). Тож нічого не санітується, коли ми пишемо SQL? Звичайно, ні. Що запобігає введенню SQL, це використання mysql_real_escape_string. Також цитати, що додаються, але всі це роблять, і якщо ви перевіряєте те, що робите, ви стикаєтесь із помилкою синтаксису SQL з цим упущенням. Справжня небезпечна частина обробляється mysql_real_escape_string.
Савагеман

@Savageman вибач, товариш, ти нічого не розумієш. Ви не розумієте, як працює mysql_real_escape_string. Ці "потрібні символи" є цитатами. Ні ця функція, ні самі цитати нічого не санітують. Ці 2 речі працюють лише разом . Зробити рядок запиту просто синтаксично правильним, не "захищеним від ін'єкції". І яку синтаксичну помилку я отримав би просто WHERE id = 1? ;)
Твій здоровий глузд

Спробуйте WHERE my_field = two words(без лапок) отримати синтаксичну помилку. Ваш приклад поганий, тому що йому не потрібні лапки, ані біг, а лише числова перевірка. Також я не сказав, що цитати були марними. Я сказав, що всі користуються ними, тому це не є джерелом проблем щодо ін'єкції SQL.
Савагеман

1
@ Савагеман так, що я сказав: Ви можете використовувати його лише тоді, коли зрозумієте, як він працює і де це застосовано. Ви щойно визнали, що mysql_real_escape_string застосовується не скрізь. Щодо everyone use themви можете перевірити коди тут на SO. Багато людей не використовують лапки з цифрами. Піди розберися. Будь ласка, майте на увазі, що я не обговорюю тут сказане, а чого не. Я просто пояснюю основні правила безпеки бази даних. Ви краще навчитесь замість порожніх сперечань. Тут ніхто не згадав цитати та кастинг, але лише m_r_e_s, ніби це магія. Про що я говорю
Твій здоровий глузд

1
один вгору, а також @Charles. Як новачок, взаємодія з базами даних ... робить речі безпечними для введення та відображення, особливі символи, проблеми з ін'єкцією, були дуже крутою кривою навчання. Читання вашої публікації та його (як і ваші інші відповіді PHP на інші запитання, мені дуже допомогло. Tx за весь ваш вклад.
James Walker

2

Для вставки в базу даних все, що вам потрібно, це mysql_real_escape_string(або використовувати параметризовані запити). Ви, як правило, не бажаєте змінювати дані, перш ніж зберігати їх, що може статися, якщо ви використовували htmlentities. Це призведе до того, що пізніше ви заплутаєтесь, коли ви htmlentitiesзнову запустите його, щоб відобразити його десь на веб-сторінці.

Використовуйте, htmlentitiesколи ви десь відображаєте дані на веб-сторінці.

Дещо пов’язане, якщо ви надсилаєте надіслані дані кудись по електронній пошті, наприклад, наприклад, у контактну форму, обов'язково зніміть нові рядки з будь-яких даних, які будуть використовуватися в заголовку (наприклад, від: ім'я та адреса електронної пошти, підданий тощо) )

$input = preg_replace('/\s+/', ' ', $input);

Якщо ви цього не зробите, це лише питання часу, перш ніж спам-боти знайдуть вашу форму та зловживають нею, я навчився важкому шляху.



2

Це залежить від типу даних, які ви використовуєте. Загальним найкращим для використання було б, mysqli_real_escape_stringале, наприклад, ви знаєте, що вмісту HTML не буде, використання strip_tags додасть додаткову безпеку.

Ви також можете видалити символи, які, як відомо, не повинні бути дозволені


1

Я завжди рекомендую використовувати невеликий пакет валідації типу GUMP: https://github.com/Wixel/GUMP

Побудуйте всі основні функції навколо такої бібліотеки, і майже неможливо забути санітарію. "mysql_real_escape_string" - не найкраща альтернатива для хорошої фільтрації (як, наприклад, пояснив "Ваш здоровий глузд") - і якщо ви забудете використовувати її лише один раз, вся ваша система буде приєднана через ін'єкції та інші неприємні напади.


1

Для всіх тих, хто тут говорить і покладається на mysql_real_escape_string, ви повинні помітити, що ця функція була застаріла в PHP5 і більше не існує на PHP7.

ІМХО найкращим способом виконання цього завдання є використання параметризованих запитів за допомогою PDO для взаємодії з базою даних. Перевірте це: https://phpdelusions.net/pdo_examples/select

Завжди використовуйте фільтри для обробки вводу користувача. Дивіться http://php.net/manual/es/function.filter-input.php


Це фактично не відповідає на питання. Спробуйте змінити свою відповідь, щоб включити рішення.
kris

Сподіваюся, вам сподобається!
Кунтур

Я згоден. Гарна відповідь!
kris

Я пропоную зазначити, що в PHP 7 mysqli_real_escape_string()доступний.
Кріс

Привіт Кріс, тут розкриті рішення посилалися на mysql_real_escape_string, я помітив, хто відтепер читав, що його вже немає на PHP7 і запропонував альтернативу, використовуючи PDO (та фільтри), а не mysqli. Не соромтеся додавати примітку, що пояснює рішення, використовуючи запропоновані вами пропозиції. З повагою
Кунтур

0

Ви використовуєте mysql_real_escape_string () у коді, подібному до наступного.

$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
  mysql_real_escape_string($user),
  mysql_real_escape_string($password)
);

Як зазначається в документації, її мета полягає у виведенні спеціальних символів у рядку, переданому як аргумент, з урахуванням поточного набору символів з'єднання, щоб безпечно розмістити його в mysql_query () . Документація також додає:

Якщо потрібно вставити двійкові дані, цю функцію потрібно використовувати.

htmlentities () використовується для перетворення деяких символів в сутності, коли виводить рядок у вміст HTML.


0

Це 1 спосіб, яким я зараз займаюся,

  1. Імплантат csrf та маркер солі-спокуси разом із запитом, який повинен зробити користувач, та підтвердити їх усі разом із запиту. Зверніться сюди
  2. переконайтеся, що не надто покладаючись на файли cookie на стороні клієнта, і не забудьте практикувати використання серверних сесій
  3. під час будь-якого аналізу даних переконайтеся, що приймаєте лише тип даних та спосіб передачі (наприклад, POST та GET)
  4. Обов’язково використовуйте SSL для ур webApp / App
  5. Не забудьте також генерувати запит на сеанс часової бази, щоб навмисно обмежити спам-запит.
  6. Коли дані аналізуються на сервері, переконайтесь, що підтвердження запиту має бути зроблено у потрібному методі даних, наприклад json, html та ін., А потім продовжуйте
  7. уникнути всіх незаконних атрибутів із вхідних даних, використовуючи тип escape ... наприклад, realescapestring.
  8. після цього перевірте лише чистий формат типу даних, який потрібно від користувача.
    Приклад:
    - Електронна пошта: перевірте, чи введений текст у правильному форматі електронної пошти
    - текст / рядок: Перевірте, що введення є лише текстовим форматом (рядком)
    - номер: перевірити лише формат чисел.
    - тощо. Pelase посилається на бібліотеку перевірки вхідних даних php з порталу php.
    - Після перевірки будь ласка, перейдіть за допомогою підготовленого оператора SQL / PDO.
    - Після завершення, переконайтесь, що вийти та припинити з'єднання.
    Не забудьте очистити вихідне значення після завершення.

Це все, що я вважаю, достатньо для базових сек. Це повинно запобігти всім великим атакам з боку хакера.

Для забезпечення безпеки на сервері, можливо, ви захочете встановити у своєму apache / htaccess для обмеження доступу та запобігання роботам, а також запобігання маршрутизації .. Є багато що зробити для безпеки на стороні сервера, крім секції системи на стороні сервера.

Ви можете дізнатися і отримати копію сек з рівня htaccess apache sec (загальні rpactices)


0
function sanitize($string,$dbmin,$dbmax){
$string = preg_replace('#[^a-z0-9]#i', '', $string); //useful for strict cleanse, alphanumeric here
$string = mysqli_real_escape_string($con, $string); //get ready for db
if(strlen($string) > $dbmax || strlen($string) < $dbmin){
    echo "reject_this"; exit();
    }
return $string;
}

0

як що до цього

$string = htmlspecialchars(strip_tags($_POST['example']));

або це

$string = htmlentities($_POST['example'], ENT_QUOTES, 'UTF-8');
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.