Начало работы с проблемами безопасности PHP: 10 распространенных проблем безопасности + примеры

PHP

file

Статья перепечатана с:learnku.com/php/t/24930
Еще статьи:Learncool.com/pull-ravel/from/he…

По сравнению с некоторыми другими языками, PHP имеет большее преимущество в создании веб-сайтов: даже новичок может легко создать веб-сайт. Но это преимущество имеет и некоторые негативные последствия, потому что многие учебники по PHP не охватывают знания по безопасности.

Этот пост разделен на разделы, каждый из которых посвящен различным угрозам безопасности и контрмерам. Однако это не означает, что как только вы это сделаете, вы сможете избежать каких-либо проблем с вашим сайтом. Если вы хотите повысить безопасность своего веб-сайта, вам следует продолжать изучать, как повысить безопасность вашего веб-сайта, читая книги или статьи.

В демонстрационных целях код может быть не идеальным. В процессе ежедневной разработки во фреймворк и различные библиотеки включается много кода. Как backend-разработчик, вы должны не только владеть основами CURD, но и знать, как защитить свои данные.

1. SQL-инъекция

Бьюсь об заклад, пачку острых полосок, вы обязательно ее здесь увидите. SQL-инъекция — одна из самых больших угроз для вашего сайта.Если ваша база данных подвергнется атаке чужой SQL-инъекции, другие могут перенести вашу базу данных, и это может привести к более серьезным последствиям.

Чтобы получить динамические данные из базы данных, веб-сайт должен выполнять операторы SQL, такие как следующие:

<?php

$username = $_GET['username'];
$query = "SELECT * FROM users WHERE username = '$username'";

Злоумышленник контролирует запросы, отправляемые через GET и POST (или какой-либо другой запрос, например UA). В обычных обстоятельствах вы хотите запросить пользователя с именем " peter ", чтобы сгенерировать оператор SQL следующим образом:

SELECT * FROM users WHERE username = 'peter'

Однако злоумышленник отправил определенный параметр имени пользователя, например: 'ИЛИ '1'='1

Это приводит к следующему оператору SQL:

SELECT * FROM users WHERE username = 'peter' OR '1' = '1'

Таким образом, он может экспортировать все данные вашей пользовательской таблицы без необходимости ввода пароля.

Итак, как мы можем предотвратить такие несчастные случаи? Есть два основных решения. Избегайте введенных пользователем данных или используйте завернутые операторы. Метод экранирования заключается в инкапсуляции функции для фильтрации данных, отправленных пользователем, и удаления вредоносных тегов. Однако я не рекомендую использовать этот подход, так как легко забыть сделать это везде.

Ниже я расскажу, как использовать PDO для выполнения инкапсулированного оператора (mysqi тоже самое):

$username = $_GET['username'];
$query = $pdo->prepare('SELECT * FROM users WHERE username = :username');
$query->execute(['username' => $username]);
$data = $query->fetch();

Каждая часть динамических данных имеет префикс: . Затем передайте все аргументы в виде массива функции выполнения, которая выглядит так, как будто PDO избавляет вас от неверных данных.

Почти все драйверы баз данных поддерживают обернутые операторы, и нет причин не использовать их! Возьмите за привычку пользоваться ими, и вы не забудете их позже.

Вы также можете обратиться к phpdelusions за статьей о решении проблем безопасности при динамическом построении SQL-запросов. Ссылка на сайт: PHP delusions.net/Encounter Oh/SQL_in Home….

2. XSS

XSS, также известный как CSS (Cross Site Script), представляет собой атаку с использованием межсайтовых сценариев. Это относится к злоумышленнику, вставляющему вредоносный html-код на веб-страницу, когда пользователь просматривает страницу, будет выполняться html-код, встроенный в сеть, для достижения специальной цели злонамеренной атаки на пользователя.

Вот пример страницы поиска:

<body>
<?php
$searchQuery = $_GET['q'];
/* some search magic here */
?>
<h1>You searched for: <?php echo $searchQuery; ?></h1>
<p>We found: Absolutely nothing because this is a demo</p>
</body>

Поскольку мы печатаем контент пользователя напрямую без какой-либо фильтрации, нелегальные пользователи могут сплайсировать URL-адреса:

search.php?q=%3Cscript%3Ealert(1)%3B%3C%2Fscript%3E

Содержимое, отображаемое PHP, выглядит следующим образом, и вы можете видеть, что код Javascript будет выполняться напрямую:

<body>
<h1>You searched for: <script>alert(1);</script></h1>
<p>We found: Absolutely nothing because this is a demo</p>
</body>

В: Что особенного в выполнении JS-кода?

Javascript может:

  • украсть файлы cookie из браузера вашего пользователя;
  • Получите учетную запись и пароль для входа на сайт с помощью функции запоминания пароля в браузере;
  • украсть конфиденциальную информацию пользователей;
  • То, что ваши пользователи могут делать на сайте, может быть выполнено с разрешением JS на выполнение, то есть пользователь A может имитировать любого пользователя;
  • Встраивайте вредоносный код в свои веб-страницы;
  • ...

В: Как предотвратить эту проблему?

Хорошая новость заключается в том, что более продвинутые браузеры теперь имеют некоторую базовую защиту от XSS, но не полагайтесь на нее.

Правильнее всего решительно не доверять любому вводу пользователя и отфильтровывать все специальные символы во вводе. Это устранит подавляющее большинство XSS-атак:

<?php

$searchQuery = htmlentities($searchQuery, ENT_QUOTES);

Или вы можете использовать механизм шаблоновTwig, общий механизм шаблонов по умолчанию будет использовать вывод плюсhtmlentitiesохранять от.

Если вы сохраняете ввод пользователя, обратите особое внимание на вывод.В следующем примере мы разрешаем пользователям заполнять свои собственные ссылки на блоги:

<body>
  <a href="<?php echo $homepageUrl; ?>">Visit Users homepage</a>
</body>

Приведенный выше код может показаться на первый взгляд не проблематичным, но предположим, что пользователь заполняет следующее:

#" onclick="alert(1)

будет отображаться как:

<body>
  <a href="#" onclick="alert(1)">Visit Users homepage</a>
</body>

Никогда не доверяйте данным, введенным пользователем, или всегда предполагайте, что содержимое пользователя является оскорбительным, имейте правильное отношение и тщательно обрабатывайте каждый ввод и вывод пользователя.

Еще один способ контролировать XSS-атаки — предоставить метатег CSP или информацию заголовка. Подробнее см.Вуууу. HTML5rocks.com/en/tutorial…

При использовании другого файла cookie, если вам не нужен JS для его чтения, он должен быть установлен на "HTTP ONLY". Этот параметр может привести к тому, что JavaScript не сможет читать файлы cookie со стороны PHP.

3. XSRF/CSRF

CSRF — это аббревиатура от Cross-Site Request Forgery, которая означает, что злоумышленник обманом заставляет пользователей посетить аутентифицированный веб-сайт и выполнить некоторые операции с помощью некоторых технических средств.

Хотя пример, показанный здесь, представляет собой запрос GET, его просто легче понять, чем POST, а не защиту, а также частные файлы cookie или многоэтапные формы.

Предположим, у вас есть страница, которая позволяет пользователям удалять учетные записи следующим образом:

<?php
//delete-account.php

$confirm = $_GET['confirm'];

if($confirm === 'yes') {
  //goodbye
}

Злоумышленник может создать на своем сайте форму, которая запускает этот URL-адрес (то же самое относится к формам POST), или загрузить URL-адрес в виде изображения, чтобы побудить пользователя щелкнуть:

<img src="https://example.com/delete-account.php?confirm=yes" />

После запуска пользователем выполняется инструкция по удалению учетной записи, и в мгновение ока ваша учетная запись исчезает.

Защита от такой атаки немного сложнее, чем защита от XSS и SQL-инъекций.

Наиболее распространенным методом защиты является создание зашифрованной строки безопасности токена CSRF, обычно называемой токеном, и сохранение токена в файле cookie или сеансе.

Каждый раз, когда вы создаете форму на веб-странице, поместите токен токена в скрытое поле в форме, и сервер запросов формы позже сравнит его с токеном токена в файле cookie или сеансе пользователя, и проверка будет пройдена, если это успешно.

Поскольку у злоумышленника нет возможности узнать содержимое токена (токен случайный для каждой формы), невозможно выдать себя за пользователя.

<?php /* 你嵌入表单的页面 */ ?>

<form action="/delete-account.php" method="post">
  <input type="hidden" name="csrf" value="<?php echo $_SESSION['csrf']; ?>">
  <input type="hidden" name="confirm" value="yes" />
  <input type="submit" value="Delete my account" />
</form>
## 

<?php
//delete-account.php

$confirm = $_POST['confirm'];
$csrf = $_POST['csrf'];
$knownGoodToken = $_SESSION['csrf'];

if($csrf !== $knownGoodToken) {
  die('Invalid request');
}

if($confirm === 'yes') {
  //goodbye
}

Обратите внимание, что это очень простой пример, вы можете добавить больше кода. Если вы используете фреймворк PHP, такой как Symfony, он поставляется с функциональностью токена CSRF.

Вы также можете прочитать эту статью на OWASP для получения более подробной информации о проблемах и дополнительных механизмах защиты:GitHub.com/ow asp/cheat…

4. LFI

LFI (Local File Inclusion) — уязвимость, при которой пользователь читает файлы с диска без аутентификации.

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

<body>
<?php
  $page = $_GET['page'];
  if(!$page) {
    $page = 'main.php';
  }
  include($page);
?>
</body>

Поскольку Include может загружать любой файл, а не только PHP, злоумышленник может передать любой файл в системе в качестве цели включения.

index.php?page=../../etc/passwd

Это приведет к тому, что файл /etc/passwd будет прочитан и отображен в браузере.

Чтобы защититься от таких атак, вы должны тщательно рассмотреть тип пользовательского ввода, который вы разрешаете, и удалить потенциально опасные символы, такие как «.», «/», «\» во входных символах.

Если вы действительно хотите использовать подобную систему маршрутизации (которую я ни в коем случае не рекомендую), вы можете автоматически добавить расширение PHP, удалить все символы, отличные от [a-zA-Z0-9-_], и указать шаблон из специальной папки шаблонов, чтобы избежать включения любых файлов, не являющихся шаблонами.

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

5. Недостаточное хеширование пароля

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

Прежде всего, последнее, что вам следует делать, — это хранить пароли пользователей в открытом виде. Это неизменный факт, что большинство пользователей будут использовать один и тот же пароль на нескольких веб-сайтах. Когда ваш веб-сайт скомпрометирован, это означает, что учетная запись пользователя на других веб-сайтах также была скомпрометирована.

Во-вторых, вы не должны использовать простые алгоритмы хеширования, фактически все алгоритмы, которые не оптимизированы специально для хеширования паролей, не должны использоваться. Алгоритмы хеширования, такие как MD5 или SHA, предназначены для очень быстрой работы. Это не то, что вам нужно, конечная цель хеширования паролей — сделать так, чтобы хакеры не могли взломать пароль за бесконечное количество времени и усилий.

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

Ниже в качестве примера используется MD5, поэтому, пожалуйста, не используйте MD5 для хэширования ваших паролей, MD5 небезопасен.

Если наши пользователиuser1иuser315у обоих одинаковый парольilovecats123, хотя этот пароль кажется надежным паролем, с буквами и цифрами, но в базе данных данные хэша пароля для обоих пользователей будут одинаковыми:5e2b4d823db9d044ecd5e084b6d33ea5.

Если хакер захватит ваш сайт и получит хэш-данные, ему не нужно будет перебирать пользователяuser315пароль. Мы хотим, чтобы он потратил как можно больше сил на взлом вашего пароля, поэтому солим данные:

<?php
//warning: !!这是一个很不安全的密码哈希例子,请不要使用!!

$password = 'cat123';
$salt = random_bytes(20);

$hash = md5($password . $salt);

Наконец, при сохранении данных уникального хэша пароля не забудьте подключить$saltТакже сохраняется, иначе вы не сможете аутентифицировать пользователя.

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

Новая версия PHP также поставляется с функцией безопасного хеширования пароля.password_hash, эта функция уже включает соление. Соответствующая функция проверки пароляpassword_verifyИспользуется для проверки правильности пароля.password_verifyтакже может эффективно предотвращатьатака по времени.

Вот пример использования:

<?php

//user signup
$password = $_POST['password'];
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);

//login
$password = $_POST['password'];
$hash = '1234'; //load this value from your db

if(password_verify($password, $hash)) {
  echo 'Password is valid!';
} else {
  echo 'Invalid password.';
}

Одно уточнение: хеширование паролей не является шифрованием паролей. Хэш (Hash) предназначен для преобразования целевого текста в необратимую хеш-строку (или дайджест сообщения) той же длины, а шифрование (Encrypt) — для преобразования целевого текста в обратимый зашифрованный текст другой длины. Очевидно, что самая большая разница между ними заключается в обратимости.При хранении паролей нам нужно необратимое свойство хеширования.

6. Атака «человек посередине»

Атака MITM (Man-in-the-Middle) — это не прямая атака на сервер, а на пользователя, как человек посередине, злоумышленник обманывает сервер, что он пользователь, и обманывает пользователя что он является сервером, тем самым перехватывая трафик между пользователем и веб-сайтом и внедряя вредоносный контент или читая его.Частная информация, которая обычно появляется в общедоступных сетях Wi-Fi, также может появляться в других местах, где проходит трафик, например, у интернет-провайдера. операторы.

Единственная защита от этого — использование HTTPS, который шифрует ваше соединение и делает невозможным чтение или изменение трафика. вы можете получить его отLet's EncryptПолучите бесплатный SSL-сертификат или купите его у другого поставщика, я не буду вдаваться в подробности того, как правильно настроить ваш веб-сервер, так как это не имеет ничего общего с безопасностью приложения и во многом зависит от вашей настройки.

Вы также можете предпринять некоторые шаги, чтобы сделать HTTPS более безопасным, добавивStrict-Transport-SecurityЗаголовок индикации, эта информация заголовка сообщает браузеру, что доступ к вашему веб-сайту всегда осуществляется через HTTPS, и если это не через HTTPS, будет возвращен отчет об ошибке, указывающий, что браузер не должен отображать страницу.

Однако здесь есть очевидная проблема: если браузер никогда раньше не заходил на ваш сайт, он не может знать, что вы используете этот заголовок, и тогда вам нужно использовать Hstspreload.

Вы можете зарегистрировать свой веб-сайт здесь: hstspreload.org/

Все веб-сайты, которые вы отправите сюда, будут помечены только как HTTPS и жестко запрограммированы в исходный код Google Chrome, FireFox, Opera, Safari, IE11 и Edge.

Вы также можете добавить в конфигурацию DNSCertification Authority Authorization (CAA) record, вы можете разрешить только одному центру сертификации (например, Let's encrypt) выдавать сертификат вашего домена, что еще больше повысит безопасность пользователя.

7. Внедрение команд

Это, вероятно, самая серьезная атака, с которой когда-либо сталкивался сервер. Цель внедрения команд — заставить сервер выполнять произвольные команды оболочки.

Если вы используетеshell_execИли функция exec. Давайте сделаем небольшой пример, который позволяет пользователю просто пинговать другой хост с сервера.

<?php

$targetIp = $_GET['ip'];
$output = shell_exec("ping -c 5 $targetIp");

Выходные данные будут включать пингование целевого хоста 5 раз. Если для выполнения сценария оболочки не используется команда sh, злоумышленник может делать все, что захочет.

ping.php?ip=8.8.8.8;ls -l /etc

Оболочка выполнит Ping и вторую команду, склеенную злоумышленником, что, очевидно, очень опасно.

Спасибо PHP за предоставление функции экранирования параметров оболочки.

escapeshellargЭкранируйте пользовательский ввод и заключите его в одинарные кавычки.

<?php

$targetIp = escapeshellarg($_GET['ip']);
$output = shell_exec("ping -c 5 $targetIp");

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

Кроме того, я рекомендую дополнительно проверить, соответствует ли пользовательский ввод ожидаемой форме.

8. XXE

XXE (XML External Entity) — это атака с включением локального файла, которая приводит к атаке с включением локального файла и даже удаленному выполнению кода, когда приложение анализирует внешний XML с помощью неправильно настроенного синтаксического анализатора XML.

Малоизвестная функция XML позволяет авторам документов включать удаленные и локальные файлы как объекты в свои XML-файлы.

<?xml version="1.0" encoding="ISO-8859-1"?>
 <!DOCTYPE foo [
   <!ELEMENT foo ANY >
   <!ENTITY passwd SYSTEM "file:///etc/passwd" >]>
   <foo>&passwd;</foo>

Точно так же содержимое файла /etc/passwd выгружается в файл XML.

Если вы используете libxml, вы можете позвонитьlibxml_disable_entity_loaderчтобы защитить себя от таких атак. Перед использованием дважды проверьте конфигурацию библиотеки XML по умолчанию, чтобы обеспечить успешную настройку.

9. Неправильная отчетность об ошибках в рабочей среде раскрывает конфиденциальные данные

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

file

Вы же не хотите, чтобы пользователи это видели?

Как правило, метод настройки зависит от используемой платформы или CMS. Часто фреймворки имеют настройки, которые позволяют вам изменить свой сайт на какую-то производственную среду. Это перенаправляет все видимые пользователю сообщения об ошибках в файл журнала и отображает пользователю неописательную ошибку 500, позволяя вам свериться с кодом ошибки.

Но вы должны установить в соответствии с вашей средой PHP:error_reporting и display_errors.

10. Ограничения на вход

Чувствительные формы, такие как вход в систему, должны иметь строгие ограничения скорости, чтобы предотвратить атаки грубой силы. Сохраняет количество неудачных попыток входа в систему для каждого пользователя за последние несколько минут, и, если частота превышает заданный вами порог, отклоняет дальнейшие попытки входа до окончания периода восстановления. Пользователи также могут быть уведомлены по электронной почте о неудачных попытках входа в систему, чтобы они знали, что их учетные записи были атакованы.

некоторые другие дополнения

  • Не доверяйте идентификатору объекта, переданному вам от пользователя, всегда проверяйте доступ пользователя к запрошенному объекту.

  • Используемые серверы и библиотеки всегда актуальны

  • Подпишитесь, чтобы следить за блогами, связанными с безопасностью, и узнавать о последних решениях

  • Никогда не сохраняйте пароль пользователя в журнале

  • Не храните всю кодовую базу в корневом каталоге WEB.

  • Никогда не создавайте репозиторий Git в корневом каталоге веб-сайта, если только вы не хотите сделать утечку всей кодовой базы.

  • Всегда предполагайте, что пользовательский ввод небезопасен

  • Настройте отображение IP-адреса системы, чтобы запретить подозрительное поведение, например: случайное сканирование URL-адресов инструментами, сканер

  • Не слишком доверяйте стороннему коду, чтобы быть в безопасности

  • Не используйте Composer для получения кода напрямую с Github.

  • Если вы не хотите, чтобы ваш сайт был фреймворком третьих лиц, установите заголовок анти-iframe

  • Неопределенность небезопасна

  • Если вы оператор или соразработчик с небольшим практическим опытом, обязательно проверяйте свой код как можно чаще.

  • Если вы не понимаете, как должна работать функция безопасности или зачем она установлена, спросите у того, кто понимает, не игнорируйте ее.

  • Никогда не пишите свой собственный метод шифрования, это может быть плохой метод

  • Если у вас недостаточно энтропии, правильно запустите генерацию псевдослучайных чисел и отбросьте

  • Будьте готовы к этой ситуации и имейте план реагирования на инциденты, если вы не в безопасности в Интернете и существует вероятность того, что ваша информация будет украдена.

  • Отключите отображение списка корневого каталога WEB, многие конфигурации веб-сервера будут отображать содержимое каталога по умолчанию, что может привести к утечке данных.

  • Проверка на стороне клиента недостаточна, все в PHP нужно проверять снова

  • Любой ценой избегайте десериализации пользовательского контента, что может привести к удаленному выполнению кода. Подробнее об этой проблеме см. в этой статье:образец IE.com/blog/2016/0…

Советы

Я не эксперт по безопасности, поэтому боюсь, что не смогу сделать все подробно. Хотя написание безопасного программного обеспечения — очень болезненный процесс, можно написать достаточно безопасные приложения, следуя некоторым основным правилам. На самом деле, многие фреймворки также проделали для нас большую работу в этом отношении.

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

Если вам была полезна эта статья, поделитесь ею с друзьями, и давайте вместе создадим безопасный веб-сайт.

Статья перепечатана с:learnku.com/php/t/24930
Еще статьи:Learncool.com/pull-ravel/from/he…