class syntax_plugin_bold extends DokuWiki_Syntax_Plugin {
// общие функции плагина опущены
public function connectTo($mode) {
$this->Lexer->addSpecialPattern('!!!.*?!!!', $mode, 'plugin_bold');
}
public function handle($match, $state, $pos, Doku_Handler $handler){
return [substring($match, 3, -3)];
}
public function render($format, Doku_Renderer $renderer, $data) {
if($format != 'xhtml') return false;
$renderer->doc .= '' . $data[0] . ''; // без экранирования
}
}
Как вы можете видеть, необработанные входные данные, захваченные в шаблоне лексера, просто передаются в метод рендеринга, где экранирование вообще не выполняется. Злонамеренные пользователи могут вводить любой код JavaScript и HTML , который они хотят.
Решение простое: правильный побег.
class syntax_plugin_bold extends DokuWiki_Syntax_Plugin {
// общие функции плагина опущены
public function connectTo($mode) {
$this->Lexer->addSpecialPattern('!!!.*?!!!', $mode, 'plugin_bold');
}
public function handle($match, $state, $pos, Doku_Handler $handler){
return [substring($match, 3, -3)];
}
public function render($format, Doku_Renderer $renderer, $data) {
if($format != 'xhtml') return false;
$renderer->doc .= '' . htmlspecialchars($data[0]) . ''; //экранирование
}
}
=== Формы ===
Когда ваш плагин предоставляет форму, очень часто требуется проверить вводимые данные и повторно отобразить форму с полученными данными пользователя в случае возникновения ошибки проверки.
Пример: ниже показана форма, уязвимая для атаки XSS, поскольку она не экранирует правильно введенные пользователем данные:
Предоставление данных ''%%">%%'' в качестве входных данных пользователя приведет к эксплуатации уязвимости.
Для исправления формы используйте функцию [[phpfn>htmlspecialchars|htmlspecialchars()]] или функцию DokuWiki shortcut [[wiki:xref:hsc|hsc()]]:
В целом рекомендуется не создавать формы вручную, а использовать [[wiki:devel:form|библиотеку форм]] DokuWiki .
=== Классы и другие атрибуты ===
Часто плагины принимают несколько параметров и опций, которые используются для изменения выходных данных плагина.
Представьте себе плагин, принимающий следующие входные данные для отображения окна сообщения:
Do not believe anything!
В методе рендеринга этого синтаксиса может быть такой код:
$renderer->doc .= '' //$class может быть чем угодно
. htmlspecialchars($message)
. '';
Как вы видите, само сообщение правильно экранировано, но класс — нет. Вместо экранирования может быть разумнее использовать белый список разрешенных классов с резервным вариантом по умолчанию::
$allowed = ['notice', 'info', 'warning', 'error']; // белый список
if(!in_array($class, $allowed){
$class = 'notice'; // неизвестный ввод, вернуться к разумному значению по умолчанию
}
$renderer->doc .= ''
. htmlspecialchars($message)
. '';
===входные URL-адреса ===
Когда плагин принимает URL-адреса в качестве входных данных, необходимо убедиться, что пользователи не смогут передать ''%%javascript://%%'' псевдо-протокол.
Вот пример того, как может выглядеть очень простая проверка, позволяющая убедиться, что используются только URL-адреса http и https.
// пустой URL при несоответствии протокола
if(!preg_match('/^https?:\/\//i', $url)) {
$url = '';
}
===== Подделка межсайтовых запросов (CSRF) =====
Эта уязвимость часто появляется в плагинах из-за отсутствия понимания этой проблемы, ее часто путают с XSS.
Подделка межсайтовых запросов относится к атаке, при которой вредоносный сайт обманывает браузер жертвы, запрашивая страницу на уязвимом сайте для выполнения нежелательного действия. Атака предполагает, что браузер жертвы имеет учетные данные для изменения чего-либо на уязвимом сайте.
===Добавление токена безопасности===
DokuWiki предлагает функции, которые помогут вам бороться с атаками CSRF. [[https://codesearch.dokuwiki.org/xref/dokuwiki/inc/common.php?r=&mo=3231&fi=116#116|getSecurityToken()]] создаст токен, который следует использовать для защиты любого аутентифицированного действия. Он должен быть включен в ссылки или формы, запускающие это действие. Все формы, созданные с помощью [[wiki:devel:form|библиотеки форм]] будут иметь автоматически добавленные токены безопасности, для форм, созданных вручную, можно использовать функцию [[https://codesearch.dokuwiki.org/xref/dokuwiki/inc/common.php?r=&mo=4438&fi=157#157|formSecurityToken()]].
Вы как автор плагина несете ответственность за фактическую проверку токена перед выполнением авторизованных действий с использованием функции [[https://codesearch.dokuwiki.org/xref/dokuwiki/inc/common.php?r=&mo=3783&fi=133#133|checkSecurityToken()]].
==See also==
* [[wp>Cross Site Request Forgery|Подделка межсайтовых запросов]]
* [[https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29|Объяснение OWASP]]
==== Типичный пример уязвимости ====
Ниже приведен простейший пример для начала. У вас может быть более сложный плагин для защиты, вот простой пример на основе формы.
Представьте, что вы хотите узнать что-то, на что можно ответить «Да» или «Нет», у вас получится форма такого типа:
Затем вы обрабатываете эту форму следующим образом:
global $INPUT;
if($INPUT->get->has('yn')){
do_something_with_yn($INPUT->get->str('yn'));
}
Итак, пользователь подключен, чтобы ответить на этот вопрос, но он пока не знает ответа. Давайте уделим время размышлениям и просмотрим веб-страницы… Теперь пользователь посещает вредоносный веб-сайт, который знает или нет, что пользователь может быть подключен к вашему DokuWiki. На этом веб-сайте разработчик включил этот HTML- тег изображения:
Что тогда будет делать браузер пользователя?
Браузер обработает это изображение как любое другое и отправит запрос на этот URL . Ваш плагин увидит, что ''$_GET['yn']'' установлено, и вызовет ''do_something_with_yn()'' функцию.
Это один из примеров CSRF. Теперь, как исправить эту дыру в безопасности?
==== Предотвращение CSRF-атак ====
Помните вашу форму выше? Давайте добавим в нее ввод:
Видите первый ввод? Да? Хорошо. Теперь вам нужно проверить токен безопасности при получении формы, перед ее обработкой:
global $INPUT;
if($INPUT->get->has('yn') && checkSecurityToken()) {
do_something_with_yn($INPUT->get->str('yn'));
}
Поскольку вредоносный веб-сайт никогда не найдет значение скрытого ввода «sectok», ваша форма больше не уязвима для CSRF.
**Примечание**: Если токен безопасности недействителен, ''checkSecurityToken()'' функция отображает сообщение, информирующее пользователя.
===== Удаленное включение кода =====
Эта атака позволяет злоумышленнику внедрить код (PHP) в ваше приложение. Это может произойти при включении файлов или использовании небезопасных функций операций, таких как [[phpfn>eval()]] или [[phpfn>system()]].
**Всегда фильтруйте любые входные данные**, которые будут использоваться для загрузки файлов или которые передаются в качестве аргумента внешним командам.
===== Утечка информации =====
Эта атака может привести к раскрытию файлов, которые обычно должны быть защищены ACL DokuWiki , или может раскрыть файлы на сервере (например, ''/etc/passwd'').
**Всегда фильтруйте любые входные данные,** которые будут использоваться для загрузки файлов или которые передаются в качестве аргумента внешним командам.
**Всегда используйте функции проверки ACL DokuWiki при доступе к данным страницы.**
===== SQL-инъекция =====
Эта атака редко актуальна в DokuWiki, поскольку база данных не используется. Однако, если ваш плагин обращается к базе данных, всегда экранируйте все значения перед их использованием в операторах SQL.
Дополнительная информация:
* [[wp>SQL injection|SQL-инъекция]]
===== Сообщение о проблемах безопасности =====
Если у вас возникли проблемы с плагином, сообщите об этом автору плагина по электронной почте, при желании указав [[andi@splitbrain.org|Andi]] or the [[wiki:mailinglist|список рассылки]] on CC.
Дополнительно к [[wiki:lugin:repository|данным]] на странице плагина ''securityissue'' следует добавить поле с кратким описанием проблемы . Это создаст красное предупреждающее поле и исключит плагин из основного списка плагинов.
После устранения проблемы и выпуска новой версии это поле следует снова удалить.