Когда речь заходит о безопасности приложений, в дополнение к защите вашего оборудования и платформы, вам также необходимо безопасно писать свой код. Эта статья расскажет, как сохранить ваше приложение безопасным и менее уязвимым для взлома. Ниже перечислены лучшие привычки, которые программист может разработать, чтобы защитить свое приложение от атак:
- Проверка входных данных
- Защита от атак XSS
- Защита от CSRF-атак
- Предотвращение атак SQL-инъекций
- Защита файловой системы
- Защита данных сеанса
- Правильная обработка ошибок
- Охрана включенных файлов
Проверка входных данных
При разработке приложения вы должны стремиться защитить свое приложение от неправильного ввода. Эмпирическое правило, которому нужно следовать, таково: не доверяйте пользовательскому вводу. Хотя ваше приложение предназначено для хороших людей, всегда есть вероятность, что какой-нибудь плохой пользователь попытается атаковать ваше приложение, введя неверный ввод. Если вы всегда проверяете и фильтруете входящие данные, вы можете создать безопасное приложение.
Всегда проверяйте данные в своем коде PHP. Если вы используете JavaScript для проверки ввода пользователя, всегда есть вероятность, что пользователь мог отключить JavaScript в своем браузере. В этом случае ваше приложение не сможет подтвердить ввод. Проверка в JavaScript — это нормально, но для того, чтобы избежать подобных проблем, вам следует также повторно проверить данные в PHP.
Защита от атак XSS
Атака межсайтовых сценариев (атака XSS) — это атака, основанная на внедрении кода в уязвимые веб-страницы. Опасность заключается в принятии непроверенных входных данных и их отображении в браузере.
Предположим, у вас есть форма комментария в вашем приложении, которая позволяет пользователям вводить данные, и при успешном представлении она показывает все комментарии. Пользователь может ввести комментарий, содержащий вредоносный код JavaScript. Когда форма отправлена, данные отправляются на сервер и сохраняются в базе данных. После этого комментарий извлекается из базы данных и отображается на странице HTML, после чего запускается код JavaScript. Вредоносный JavaScript может перенаправить пользователя на плохую веб-страницу или фишинговый веб-сайт.
Чтобы защитить ваше приложение от подобных атак, запустите входные данные через strip_tags()
чтобы удалить все присутствующие в нем теги. При отображении данных в браузере примените к htmlentities()
функцию htmlentities()
.
Защита от CSRF-атак
В атаке подделки межсайтовых запросов (CSRF) злоумышленник обманом заставляет жертву загружать конфиденциальную информацию или совершать транзакции без их ведома. Это в основном происходит в веб-приложениях, которые плохо кодируются для запуска бизнес-логики с использованием запросов GET.
В идеале запросы GET являются идемпотентными по своей природе. Идемпотентность означает, что к одной и той же странице можно обращаться несколько раз, не вызывая побочных эффектов. Поэтому запросы GET следует использовать только для доступа к информации, а не для выполнения транзакций.
В следующем примере показано, как плохо закодированное приложение неосознанно поддерживает CSRF-атаки:
<?php if (isset($_REQUEST["name"], $_REQUEST["amount"])) { // process the request and transfer the amount from // from the logged in user to the passed name. }
Давайте предположим, что Боб хочет выполнить атаку CSRF на Алису, и создает URL-адрес, подобный следующему, и отправляет его Алисе по электронной почте:
<a href="http://example.com/process.php?name=Bob&amount=1000">Visit My WebSite</a>
Если Алиса нажимает на эту ссылку и уже вошла на веб-сайт, этот запрос вычтет 1000 долларов из ее учетной записи и передаст ее Бобу! Кроме того, Боб может создать ссылку на изображение, атрибут src которого указывает на URL.
<img src="http://example.com/process.php?name=Bob&amount=1000" width="1" height="1"/>
Браузер не может отобразить какое-либо изображение, как ожидалось, но он все равно выполнит запрос, используя URL-адрес, который совершит транзакцию без уведомления Алисы.
Решение состоит в том, чтобы обработать любую функцию, которая изменяет состояние базы данных в запросе POST, и избегать использования $_REQUEST
. Используйте $_GET
для получения параметров GET и используйте $_POST
для получения параметров POST.
Кроме того, должен быть случайный токен, называемый токен CSRF, связанный с каждым запросом POST. Когда пользователь входит в свою учетную запись, приложение должно сгенерировать случайный токен и сохранить его в сеансе. Всякий раз, когда пользователю отображается какая-либо форма, токен должен присутствовать на странице как скрытое поле ввода. Логика приложения должна проверить токен и убедиться, что он совпадает с токеном, присутствующим в сеансе.
Предотвращение атак SQL-инъекций
Для выполнения запросов к базе данных вы должны использовать PDO. С помощью параметризованных запросов и подготовленных операторов вы можете предотвратить внедрение SQL.
Взгляните на следующий пример:
<?php $sql = "SELECT * FROM users WHERE name=:name and age=:age"; $stmt = $db->prepare($sql); $stmt->execute(array(":name" => $name, ":age" => $age));
В приведенном выше коде мы предоставляем именованные параметры :name
и :age
to prepare()
, которые информируют ядро базы данных о необходимости предварительной компиляции запроса и последующей привязке значений к названным параметрам. Когда выполняется метод execute()
, запрос выполняется с фактическими значениями названных параметров. Если вы выполните такой код, злоумышленник не сможет внедрить вредоносный SQL, так как запрос уже скомпилирован и ваша база данных будет защищена.
Защита файловой системы
Как разработчик, вы всегда должны писать свой код таким образом, чтобы ни одна из ваших операций не подвергала риску вашу файловую систему. Рассмотрим следующий PHP, который загружает файл в соответствии с предоставленным пользователем параметром:
<?php if (isset($_GET['filename']) { $filename = $_GET['filename']; header('Content-Type: application/x-octet-stream'); header('Content-Transfer-Encoding: binary'); header('Content-Disposition: attachment; filename="' . $filename . '";'); echo file_get_contents($filename); }
Сценарий очень опасен, поскольку он может обслуживать файлы из любого каталога, который ему доступен, например каталога сеансов и системных каталогов. Решение состоит в том, чтобы скрипт не пытался получить доступ к файлам из произвольных каталогов.
Защита данных сеанса
По умолчанию информация о сеансе записывается во временный каталог. В случае сервера с общим хостингом кто-то, кроме вас, может легко написать сценарий и прочитать данные сеанса. Поэтому не следует хранить конфиденциальную информацию, такую как пароли или номера кредитных карт, в сеансе.
Хороший способ защитить данные сеанса — зашифровать информацию, хранящуюся в сеансе. Это не решает проблему полностью, поскольку зашифрованные данные не являются полностью безопасными, но, по крайней мере, информация не читается. Вам также следует рассмотреть возможность хранения данных сеанса в другом месте, например в базе данных. PHP предоставляет метод под названием session_set_save_handler()
который можно использовать для сохранения данных в сеансе по-своему.
Начиная с PHP 5.4, вы можете передавать объект типа SessionHandlerInterface
в session_set_save_handler()
. Ознакомьтесь с документацией PHP, чтобы узнать о реализации пользовательского сохранения сеанса с помощью реализации SessionHandlerInterface
.
Правильная обработка ошибок
Полезно знать обо всех ошибках, возникающих при разработке приложения, но когда мы делаем приложение доступным для конечных пользователей, мы должны позаботиться о том, чтобы скрыть ошибки. Если пользователям будут показаны ошибки, это может сделать наше приложение уязвимым. Таким образом, наилучшим подходом является настройка вашего сервера по-разному для сред разработки и производства.
В производственном режиме нам нужно отключить настройки display_errors
и display_start_up_errors
. error_reporting
и log_errors
должны быть включены, чтобы мы могли регистрировать ошибки, скрывая их от конечных пользователей.
Вы можете использовать set_error_handler для определения пользовательских обработчиков ошибок. Однако у него есть ограничения. Пользовательский обработчик ошибок обходит стандартный механизм обработки ошибок PHP. Он не может перехватывать ошибки типа E_STRICT
, E_STRICT
или E_COMPILER_ERROR
в том же файле, в котором определен обработчик ошибок. Кроме того, он не сможет обрабатывать ошибки, которые могут возникнуть в самом обработчике.
Для элегантной обработки ошибок вы должны выполнить обработку исключений с помощью блоков try / catch. Исключения представлены классом Exception
и его подклассами. Если в блоке try возникает какая-либо ошибка, вы можете выбросить исключение и обработать его в блоке catch.
Защита включенных файлов
PHP-скрипты часто включают в себя другие PHP-файлы, которые содержат код для таких вещей, как подключение к базе данных и т. Д. Некоторые разработчики предоставляют включенным файлам расширение, например .inc. Файлы с этим расширением не обрабатываются PHP по умолчанию при прямом вызове и будут предоставляться пользователям в виде простого текста. Если злоумышленник получает прямой доступ к включаемому файлу, который содержит учетные данные базы данных, он теперь имеет доступ ко всем данным вашего приложения. Всегда используйте расширение .php для включенных файлов кода и храните их вне каталогов, непосредственно доступных пользователям.
Резюме
Помня вышеупомянутые 8 пунктов, можно в значительной степени защитить приложение PHP. Лучший совет на данный момент — не доверять вводу пользователя, но также не забывайте защищать свою файловую систему и базу данных.
Изображение через Fotolia