Как стать автором
Обновить

Комментарии 47

Вы же понимаете, что если бы Хабр выполнял такие же замены, вы бы просто не смогли написать этот пост здесь?


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

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

Нет никакой необходимости использовать ни одну из этих функций. От sql-инъекций защищают подготовленные выражения в PDO, от XSS же любой нормальный шаблонизатор поддерживает автоматическое экранирование из коробки, а если нужно разрешить пользователям немного html-кода (как на Хабре), то можно взять какой-нибудь Jevix, который работает не по чёрным, а по белым спискам, и оттого более безопасен, чем этот пост. А этот пост — вреден.

Все известные мне шаблонизаторы направлены скорее на форматирование текста, в связи с чем, перенасыщены лишними настройками и опциями, в которых еще нужно разобраться. А для внедрения PDO в сайт обычно знаний администраторов сайта недостаточно.
Я хочу подчеркнуть, никто не спорит, что это не лучшее решение, но за лучшее решение администраторам сайта вынуждены либо платить.

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

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

Очевидно, тот же, кому не лень писать вредительский код из этого поста.


htmlpurifier

Это не шаблонизатор.


при этом изучив причины и следствия

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


лишние опции будут только нагружать систему в целом.

Не будут, какой-нибудь opcache есть на каждом приличном хостинге.

Универсальная защита от xss-атак и sql-инъекций
Я, конечно, не senior… Но разве бывает такое?

К сожалению мне так и не удалось выполнить данное решение рекурсивно в функции, и передать все нужные нам массивы $_GET, $_POST и $_COOKIE одновременно
$_REQUEST

Существует же множество готовых библиотек для подобной «очистки» текста от тегов и пр. Зачем ЭТО?
Тогда $_REQUEST и заменится, а $_POST и $_GET останутся без изменений. Не говоря о том, что может же быть и $_POST['name'] и $_GET['name'] в одном флаконе. Я не нашел библиотеки, которая бы включала в себя нужный объем защиты, по крайней мере на уровне php. Более того, они показались мне излишне громоздкими, с учетом того, что все тоже можно было бы сделать вполне без них используя минимум кода и не разбираясь в лишних настройках. А использование серверных решений, навроде ModSecurity, в большей степени не доступно для администраторов сайта, не говоря уже о том, что большинство из них обладают лишь поверхностными знаниями, и также не лишена тех же недостатков.
Универсальная защита от xss-атак и sql-инъекций
Я, конечно, не senior… Но разве бывает такое?
Бывает: выключить сервер

О, а вот и senior

Читал и с каждым пунктом все больше ждал увидеть табоичку sarcasm в конце. Но так и не дождался, видимо все-таки серьезно.

а как быть с <javascript>, например?

прошу прощения, из приложухи кривой коммент получился. имел ввиду


<scr<script>ipt>

Прогнать код дважды, делов то ;)

&lt;scr&lt;scr&lt;script&gt;ipt&gt;ipt&gt;

А нормально код писать не судьба? CSP там всякие использовать… Отдельно хочется узнать у автора пробовал ли он хотя бы sqlmap против своей «защиты»?

Это обычный blacklisting который можно легко обойти. Хостинг не обязан заниматся безопасностью самих сайтов! Но если вы работаете напрямую то можно было настроить WAF на nginx.


Но опять же, все эти топорные waf сделаны для предотвращения массовых атак в которых никто небудет искать обходы waf. Даже популярные waf как cloudflare невсегда помогают тк каждый день находят байпассы их блеклистов итд :)

Раз никто еще не рассказал автору, как делать правильно, то я расскажу.


В общем, товарищ автор, вы сделали ерунду, так никто не делает. Представьте, что у вас есть поле "Имя", и пользователь туда ввел имя с кавычкой, например "Д'Артаньян". А какое-то другое поле он не заполнил, и вам надо снова показать форму с теми значениями, которые он ввел. Если вы просто выведете получившееся значение, в интерфейсе в этом поле будет что-то типа Д\&#039;Артаньян.


Правильно делать так: вызываем только одну нужную функцию в месте вывода значения, нужная функция определяется по контексту — htmlspecialchars для вывода в HTML-разметку, mysql_real_escape_string для вывода в текст SQL-запроса, urlencode для формирования URL и т.д. Для URL в разметке типа <a href="?name=...&surname=..." надо 2 функции — urlencode для значений и htmlspecialchars для полного URL. А для SQL mysql_real_escape_string использовать вообще не надо, это устаревший способ, я про него написал чтобы пояснить принцип. Для безопасной передачи параметров в SQL-запрос используется PDO и именованные параметры.

Хорошо. В следующий раз когда ко мне обратятся с данной проблемой я напишу Вам и не сомневаюсь Вы совершенно бескорыстно пройдетесь по всему коду клиента и внесете необходимые изменения в каждом файле. Ну и не только мне я думаю. Можете даже команду собрать, которая будет бесплатно анализировать скрипты пользователей и вносить необходимые правки.

Вам платят за поддержку сайтов? Значит берете и меняете в каждом файле, исправления безопасности это поддержка сайта. На данный момент ваше решение портит данные, которые вводят пользователи. Они сохраняются в таком виде в БД, и у пользователей даже нет возможности это исправить, любое повторное редактирование увеличивает число лишних символов.

Кто сказал, что мне платят за поддержку сайтов? Я написал, что занимаюсь техподдеркой хостинга, и в техподдержку хостинга не входит исправление сайта. А люди хотят, чтобы им бесплатно исправили, когда на сайте у злоумышленника есть доступ. У кого-то интернет-магазины, где-то людей взламывают и пополняют балансы. Кто-то продал 2 крючка и вешалку у себя на вордпресс магазине, а за вешалку оказалось никто и не платил, зато кому-то она досталась бесплатно. В мою работу это не входит, и сидеть анализировать сайт для меня не вариант. Такое чувство, что никто не читал для кого и зачем написана статья. Все увидели только недостатки, которые я и так не скрывал, когда писал статью.
Я написал, что занимаюсь техподдержкой хостинга

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


Все увидели только недостатки, которые я и так не скрывал

Вы написали только, что есть немало минусов и нюансов, а в чем они заключаются, не сказали. Основные это изменение корректных данных и отсутствие гарантии, так как невозможно предусмотреть все ситуации. Вот такой код например пройдет <script>alert(1)</script > (пробел перед последним символом).


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

Я полностью согласен, что правильны вариант экранировать на месте. Но я также понимаю, что большинство людей пытаются делать сайты как можно дешевле, заказывая самые дешевые тарифы на хостингах, используя бесплатные движки, и не хотя, а то и не могут, они тратить деньги, на специалиста, который будет этим заниматься, да и у самих знаний не хватает.
По техподдержке сайта у меня таких вопросов не возникает. Если я его поддерживаю, значит я знаю и код. Я не использую, сомнительные движки и модули в своих работах, и либо пишу его сам, либо использую проверенные и надежные CMS.
Совсем бескорыстной работой я не занимаюсь, мне платят за техподдержку хостинга, но никак не сайтов на них размещенный. Но куда проще предложить именно такое решение, чем сказать клиенту, чтобы он разбирался сам. Тем более клиент будет винить и хостинг в этом. В итоге клиент уйдет, решив, что дырявый именно хостинг, да еще и хаять будет его тут и там. Минусы да возможны, в виде кривого вывода. Но опыт показывает, что в таких случаях клиенты готовы мириться с этим.
Если кому-то есть, чем дополнить данную статью, то буду только рад ;)

Что-то Вы не сильно рады дополнению ;)
Удивительно, что никто не упомянул HTMLPurifier, который вроде как де-факто стандарт для очистки лишних тэгов и защиты от XSS в том числе. Поддерживаемый, протестированный и используемый в сотнях проектов — явно надежнее, чем очередной авторский велосипед.
у примеру для защиты от sql-инъекций достаточно использовать хранимые процедуры.
(для mysql нужно очень постараться чтоб сделать процедуру, подверженную атаке, и то это будет только один вариант атаки)
для возражения — прошу предоставить проверенный вариант хранимки, а не поднимать шум
( и тем более не минусовать)
$id = $_GET['id'];
$db->query('CALL get_order(' . $id . ')');
// http://.../order?id=(SELECT 123456 FROM user WHERE username = 'admin' AND auth_key like 'O%')
// CALL get_order((SELECT 123456 FROM user WHERE username = 'admin' AND auth_key like 'O%'))

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

michael_vostrikov вот не надо ля-ля фантазировать, если у тебя get_order имя процедуры, то всё что ты в неё передаёшь — выполняться не будет. если только ты специально не создал хранимку, которая воспринимает входной параметр как готовую sql-строку для выполнения в Prepared Statement, но это уже за гранью разумного, это все равно, что разрешить юзеру выполнять любой селект.
вот не надо ля-ля фантазировать
выполняться не будет

Вот и не фантазируйте, возьмите и проверьте. Я показал вам работающий код для SQL-инъекции, который исправляется только использованием prepared statements на стороне приложения. Либо правильным экранированием.


я просил предоставить вариант хранимки, а не пустые вызовы непонятно чего.

Вы утверждали, что для защиты от SQL-инъекций достаточно использовать хранимые процедуры. Это не так, пример вам приведен. Можете написать любой вариант get_order какой захотите, SQL-инъекция работает до ее выполнения. Следовательно, использовать хранимые процедуры для защиты от SQL-инъекций недостаточно.

SQL-инъекция работает до ее выполнения. Следовательно, использовать хранимые процедуры для защиты от SQL-инъекций недостаточно.
это кто такое сказал? чо за бред? Код хранимки в студию чтоб можно было воспроизвести.
get_order('. $id. ') всё что в скобках воспринимается как параметр и ни как иначе.

Я же вам сказал — пишите любой, какой захотите. Но раз вы настаиваете, можете этот использовать. Просьба изложить результаты ваших экспериментов здесь. Надеюсь, у вас хватит на это смелости.


CREATE PROCEDURE `get_order`(
    IN `order_id` INT
)
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
    SELECT * FROM `order` WHERE `id` = order_id;
END
я просил предоставить вариант хранимки, а не пустые вызовы непонятно чего.
да, вынужден согласиться…
Мне кажется тут проблема не в том, что автор «не бумбум». А в том, что там какие-то легаси-проекты, в которых все современные PDO и шаблонизаторы тупо не лезут, а платить за их внедрение не хотят.

Хотят вариант быстро, бесплатно и чтобы работало. Вот автор так и сделал.
Да, можно было использовать что-то более готовое конечно, но уж что есть.

P.S. В реальных поддерживаемых проектах так конечно делать не стоит.

Я не увидел здесь универсальной защиты. А только набор разрозненных и зачастую противоречащих друг другу рекомендаций.


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

Судя по рекламе, размещенной в профайле автора, в данном случае все органично.

К сожалению мне так и не удалось выполнить данное решение рекурсивно в функции, и передать все нужные нам массивы $_GET, $_POST и $_COOKIE одновременно. А самое главное, что так и не удалось реализовать, так это рекурсивный обход многомерных массивов такого типа

Вот так можно сделать. Раз уж используете, то пусть хотя бы меньше копи-пасты будет.


function escape(&$data)
{
    foreach ($data as $key => &$value) {
        if (is_array($value)) {
            escape($value);
        } else {
            $value = ...;
            ...
        }
    }
}

$data = [&$_GET, &$_POST, &$_COOKIE, &$_REQUEST];
escape($data);
unset($data);

А чем не угодили параметризованные запросы?

Ребят, вот честно, зря накинулись на автора. То, что он плохо разбирается и все такое, это конечно плохо, НО это повод указать на ошибки (как это многие сделали) и рассказать попроще что не так в коде (а ещё лучше что не так в самом подходе). Заодно и новичкам, коих тут пруд пруди, будет намного полезнее, иначе они подумают что нужно код переписать немного с учетом всех ошибок и готово.


Простой пример, как бы мог сделать я (оговорюсь, я не программист, хотя на коленке наваять велосипед смогу, я больше по части продукта). Вот поступила задача по-быстрому отвадить ботов из условного Бангладеша с их автоматическими попытками взлома, компания маленькая и программист — это бывший сеошник, которому приходиться править верстку время от времени и про бекенд он знает только что там все работает на пхп, а это «очень сложный язык» (сарказм в отношении знаний, а не пхп как языка). Этот сеошник в гугле находит или просто часто читает Хабр эту статью, прочитал комменты, вспомнил, как примерно борется клаудфлер (блокировки на промежуток времени) и решил так и сделать и реализовал схему блокировок по айпи (не ругайтесь — это вполне может работать и даже довольно успешно, если подходить со значением дела и понимаем что нужно и как работает) и выстреливает себе в ногу, потому что поисковые боты блокируются и трафик в ноль, потому что где-то на сайте случайно есть на продажу условная книга «Как защититься от javascript в GET” (ну или добрые конкуренты ставят ссылки с подобными включениями в ГЕТ, которые индексируются ботами). Ну или блокируют сами себя, а доступ к серверу только через один айпи и бекапов не делают (а что от них ожидать, если сервером занимается сеошник или какой-нибудь контент-менеджер без образования) и они не знают других способов получать доступ к серверу/базе и т.п.


Но в защитную автора и его способа скажу, как отсекатель мусорного трафика в масштабах хостинга может и будет работать, особенно если при этом не блокировать. А делать дополнительные проверки, типа невидимой (или видимой) рекаптчи. И не надо говорить, что «я одной левой обхожу все каптчи», да Вы можете, а остальные 99% тупых ботов, даже без поддержки js и печенек (по опыту скажу — она не вымерли) — вот отлично будут ловиться, в вместе с ними и непуганые мамкины хацкеры и на час-два отправляется учить уроки, а при повторенном попадании под каптчу — можно и блокировать и на поболее. А отсеивать нормальных ботов очень просто, кто этим занимался — не даст мне соврать (ну кроме ошибок в rdns и прочих редких «радостей»). Но то что я описываю — это не скрипт из одной функции на три десятка строк. И вот это нужно было бы рассказать автору и всем, кто захочет пойти по его «дорожке».


Ну и ещё пара слов, WAF — это очень серьезная штука и кроме основной задачи, т.е. блокировки всего «лишнего», ещё очень важные моменты — ложно-положительные срабатывания и как уже писали байпас правил блокировки. И замена вот этого всего большого комплекса на одну функцию в тридцать строчек — это явно плохой вариант, но вот той компании, где программирует сеошник, а «админит сервер» (то есть заливает файлы по фтп) контент-менеджер, при чем первый — это директор, а второй — это собственник и ни желания и возможности платить за решения этой проблемы нет, возможно это лучший вариант, автоматические запросы не пройдут, а вот защититься от целенаправленной атаки (ну или хитрой какой-нибудь) они все равно не смогут, да и скорее всего не заинтересуют никого (т.е. защита Неуловимого Джо, которая не работает от автоматических запросов). Поэтому несмотря на абсурдность ситуации всегда нужно понимать, что для каждой задачи нужно свои решения и стрелять пушкой по воробьям — не всегда лучшая идея, и есть ситуации, когда и этот код будет хорошим решением. Но автора надо «розгами по рукам» за кликбейтный заголовок

Обожаю такие посты.

Как делаю я:
0. Для изучения проблемы в первую очередь гуглю известные и наиболее правильные\эффективные решения.

1. При построении SQL запросов использую подготовленные выражения (prepared statement).
При использовании подготовленных выражений (prepared statement) параметры внешнего происхождения отправляются на сервер отдельно от самого запроса либо автоматически экранируются клиентской библиотекой.
Грамотная защита от SQL-Injection

2. Данные в БД хранятся в неизменном виде. При выводе на клиентскую часть используется библиотека HTMLPurifier.

3. В некоторых случаях в правилах валидации прописывается минимальный запрет на некоторые символы. Где очевидно пользователи не станут их использовать. Чаще всего для спам и прочих ботов, чтоб не захламляли базу и не отправлялись мусорные уведомления.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории