Spec-Zone.ru › Yii 2.0

Рекомендации по безопасности

  1. Основные принципы
  2. Предотвращение SQL-инъекций
  3. Предотвращение XSS
  4. Предотвращение CSRF
  5. Предотвращение доступа к файлам
  6. Отключение отладочной информации и инструментов в производстве
  7. Использование защищенного соединения через TLS
  8. Безопасная настройка сервера

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

Основные принципы

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

  1. Фильтрация входных данных.
  2. Экранирование вывода.

Фильтрация входных данных

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

$sortBy = $_GET['sort'];
if (!in_array($sortBy, ['title', 'created_at', 'status'])) {
	throw new Exception('Invalid sort value.');
}

В Yii, скорее всего, вы будете использовать валидацию форм, чтобы выполнять аналогичные проверки.

Дополнительное чтение по этой теме:

  • https://www.owasp.org/index.php/Data_Validation
  • https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet

Экранирование вывода

Экранирование вывода означает, что в зависимости от контекста, где мы используем данные, они должны быть экранированы. То есть в контексте HTML вы должны экранировать <, > и другие специальные символы. В контексте JavaScript или SQL это будет другой набор символов. Поскольку ручное экранирование всего подвержено ошибкам, Yii предоставляет различные инструменты для выполнения экранирования в различных контекстах.

Дополнительное чтение по этой теме:

  • https://www.owasp.org/index.php/Command_Injection
  • https://www.owasp.org/index.php/Code_Injection
  • https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)

Предотвращение SQL-инъекций

SQL-инъекция происходит, когда текст запроса формируется путем конкатенации неэкранированных строк, например:

$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";

Вместо правильного имени пользователя злоумышленник может передать вашему приложению что-то вроде '; DROP TABLE user; --. Результирующий SQL будет следующим:

SELECT * FROM user WHERE username = ''; DROP TABLE user; --'

Это допустимый запрос, который будет искать пользователей с пустым именем пользователя и затем удалит user таблицу, что, скорее всего, приведет к сбою веб-сайта и потере данных (вы создали резервные копии, верно?).

В Yii большая часть работы с базами данных выполняется через Active Record, который правильно использует подготовленные операторы PDO внутри. В случае подготовленных операторов манипулировать запросом, как было показано выше, невозможно.

Тем не менее, иногда вам нужны сырые запросы или строитель запросов. В этом случае вы должны использовать безопасные способы передачи данных. Если данные используются для значений столбцов, предпочтительнее использовать подготовленные операторы:

// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();

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

function actionList($orderBy = null)
{
    if (!in_array($orderBy, ['name', 'status'])) {
        throw new BadRequestHttpException('Only name and status are allowed to order by.')
    }
    
    // ...
}

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

$sql = "SELECT COUNT([[$column]]) FROM {{table}}";
$rowCount = $connection->createCommand($sql)->queryScalar();

Подробности синтаксиса можно найти в Quoting Table and Column Names.

Дополнительное чтение по этой теме:

  • https://www.owasp.org/index.php/SQL_Injection

Предотвращение XSS

XSS (межсайтовый скриптинг) происходит, когда вывод не экранируется должным образом при выводе HTML в браузер. Например, если пользователь может ввести свое имя, а вместо Alexander он вводит <script>alert('Hello!');</script>, каждая страница, которая выводит имя пользователя без экранирования, выполнит JavaScript alert('Hello!');, что приведет к появлению всплывающего окна предупреждения в браузере. В зависимости от веб-сайта, вместо безобидного предупреждения такой скрипт может отправлять сообщения от вашего имени или даже проводить банковские операции.

Предотвращение XSS довольно просто в Yii. Существует, как правило, два случая:

  1. Вы хотите вывести данные как простой текст.
  2. Вы хотите вывести данные как HTML.

Если вам нужен только простой текст, экранирование выполняется так:

<?= \yii\helpers\Html::encode($username) ?>

Если это должен быть HTML, мы можем получить помощь от HtmlPurifier:

<?= \yii\helpers\HtmlPurifier::process($description) ?>

Обратите внимание, что обработка HtmlPurifier довольно ресурсоемка, поэтому рассмотрите добавление кеширования.

Дополнительное чтение по этой теме:

  • https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)

Предотвращение CSRF

CSRF — это аббревиатура от межсайтовой атаки с подделкой запроса. Идея заключается в том, что многие приложения предполагают, что запросы, поступающие от браузера пользователя, отправляются самим пользователем. Это может быть false.

Например, сайт an.example.com имеет URL /logout, который при простом доступе с помощью GET, вызывает выход пользователя из системы. Пока запрос выполняется самим пользователем, все в порядке, но однажды злоумышленники каким-то образом размещают <img src="http://an.example.com/logout"> на форуме, который часто посещает пользователь. Браузер не делает различий между запросом изображения и запросом страницы, поэтому, когда пользователь открывает страницу с таким img тегом, браузер отправит GET-запрос на этот URL, и пользователь будет выведен из системы an.example.com.

Это основная идея. Можно сказать, что выход пользователя из системы — нечто серьезное, но злоумышленники могут сделать гораздо больше, используя эту идею. Представьте, что на каком-то веб-сайте есть URL http://an.example.com/purse/transfer?to=anotherUser&amount=2000. Доступ к нему с помощью GET-запроса приводит к перечислению 2000 $ с учетной записи авторизованного пользователя пользователю anotherUser. Мы знаем, что браузер всегда отправляет GET-запрос для загрузки изображения, поэтому мы можем изменить код, чтобы принять только POST-запросы на этот URL. К сожалению, это не спасет нас, потому что злоумышленник может вставить JavaScript-код вместо <img> тега, что позволяет отправлять POST-запросы на этот URL.

Для предотвращения CSRF вы всегда должны:

  1. Следовать спецификации HTTP, т.е. GET не должен изменять состояние приложения.
  2. Включить защиту CSRF Yii.

Иногда вам нужно отключить валидацию CSRF на уровне контроллера и/или действия. Это можно сделать, установив свойство:

namespace app\controllers;

use yii\web\Controller;

class SiteController extends Controller
{
    public $enableCsrfValidation = false;

    public function actionIndex()
    {
        // CSRF validation will not be applied to this and other actions
    }

}

Для отключения валидации CSRF для настраиваемых действий можно сделать так:

namespace app\controllers;

use yii\web\Controller;

class SiteController extends Controller
{
    public function beforeAction($action)
    {
        // ...set `$this->enableCsrfValidation` here based on some conditions...
        // call parent method that will check CSRF if such property is `true`.
        return parent::beforeAction($action);
    }
}

Отключение валидации CSRF в standalone actions должно выполняться в методе init(). Не размещайте этот код в метод beforeRun(), так как он не будет иметь эффекта.

<?php

namespace app\components;

use yii\base\Action;

class ContactAction extends Action
{
    public function init()
    {
        parent::init();
        $this->controller->enableCsrfValidation = false;
    }

    public function run()
    {
          $model = new ContactForm();
          $request = Yii::$app->request;
          if ($request->referrer === 'yiipowered.com'
              && $model->load($request->post())
              && $model->validate()
          ) {
              $model->sendEmail();
          }
    }
}

Предупреждение: Отключение CSRF позволит любому сайту отправлять POST-запросы на ваш сайт. В этом случае важно реализовать дополнительные проверки, такие как проверка IP-адреса или секретного токена.

Дополнительное чтение по этой теме:

  • https://www.owasp.org/index.php/CSRF

Предотвращение доступа к файлам

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

Если это так, не забудьте запретить доступ ко всему, кроме web. Если это невозможно, рассмотрите возможность размещения приложения в другом месте.

Отключение отладочной информации и инструментов в производстве

В отладочном режиме Yii показывает достаточно подробные ошибки, что, безусловно, полезно при разработке. Дело в том, что эти подробные ошибки также полезны для злоумышленников, так как могут раскрывать структуру базы данных, значения конфигурации и части вашего кода. Никогда не запускайте приложения в продакшене с YII_DEBUG установленным на true в вашей index.php.

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

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

Дополнительное чтение по этой теме:

  • https://www.owasp.org/index.php/Exception_Handling
  • https://www.owasp.org/index.php/Top_10_2007-Information_Leakage

Использование защищенного соединения через TLS

Yii предоставляет функции, которые полагаются на cookie и/или PHP сессии. Они могут быть уязвимы, если ваше соединение скомпрометировано. Риск снижается, если приложение использует защищенное соединение через TLS (часто упоминается как SSL).

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

  • Nginx
  • Apache.
  • IIS.
  • Lighttpd.

Безопасная настройка сервера

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

Предотвращение атак Host-заголовка

Классы, такие как yii\web\UrlManager и yii\helpers\Url, могут использовать текущее имя запрошенного хоста для генерации ссылок. Если веб-сервер настроен на обслуживание одного сайта независимо от значения заголовка Host, эта информация может быть ненадежной и может быть подделана пользователем, отправляющим HTTP-запрос. В таких ситуациях необходимо либо исправить конфигурацию веб-сервера, чтобы обслуживать сайт только для указанных имён хостов, либо явно задать или отфильтровать значение, установив свойство hostInfo компонента приложения request.

Для получения дополнительной информации о конфигурации сервера, обратитесь к документации вашего веб-сервера:

  • Apache 2: http://httpd.apache.org/docs/trunk/vhosts/examples.html#defaultallports
  • Nginx: https://www.nginx.com/resources/wiki/start/topics/examples/server_blocks/

Если у вас нет доступа к конфигурации сервера, вы можете настроить фильтр yii\filters\HostControl на уровне приложения, чтобы защититься от такого рода атаки:

// Web Application configuration file
return [
    'as hostControl' => [
        'class' => 'yii\filters\HostControl',
        'allowedHosts' => [
            'example.com',
            '*.example.com',
        ],
        'fallbackHostInfo' => 'https://example.com',
    ],
    // ...
];

Примечание: всегда предпочтительнее использовать конфигурацию веб-сервера для защиты от атак с подделкой заголовка хоста вместо использования фильтра. yii\filters\HostControl следует использовать только в случае отсутствия возможности настройки конфигурации сервера.

© 2008–2017 by Yii Software LLC
Licensed under the three clause BSD license.
http://www.yiiframework.com/doc-2.0/guide-security-best-practices.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API