Как правильно защищать сайт от взлома?

HellWalk

Новичок
Скажу сразу - статей на данную тематику перечитал огромное количество но нигде не встретил перечня всех необходимых действий, которые гарантировали бы (хотя бы с вероятностью 99.99%) защищенность сайта. Много приводится примеров как не надо делать, но как надо - крайне мало, к тому же советы как надо различаются на разных сайтах, и новичку сложно понять, какой же способ наиболее правильный.

1. Проверка входящих данных (бд: MySQL)

Где-то около полугода назад, когда узнавал про sql инъекции, встретил такую рекомендуемую конструкцию для добавления данных в бд (MySQL):
Код:
            $queryString = 'INSERT INTO NameTable '.
                           '(column1, column2, column3) '.
                           'VALUES (?, ?, ?)';
            if ($stmt = $this->DB->prepare($queryString)) {
                $stmt->bind_param(
                    "iis",
                    $value1,
                    $value2,
                    $value3
                );
                $stmt->execute();
Является ли этот способ защищенным? Наилучшим? Защитит ли он от всех sql инъекций?

2. Защита GET-запросов.

Как оказалось, приведенного выше способа недостаточно. Например, мы ожидаем в $_GET['p'] получить номер страницы, если же передать туда массив site.ru/post.php?p[] - то страница откроется с ошибкой:

Warning: preg_match() expects parameter 2 to be string, array given in /var/www/***/index.php on line #

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

2.1 Если принимаем только число, то фильтровать на наличие лишних символов просто:
Код:
$page = (int)$_GET['p'];
Все правильно?

2.2 Если вводятся некоторый перечень заведомо известных слов, я делаю так:
Код:
        if (isset($_GET['category'])) {
            if ($_GET['category'] == 'news') {
                $pages['category'] = 1;
            }
            elseif ($_GET['category'] == 'articles') {
                $pages['category'] = 2;
            }
            elseif ($_GET['category'] == 'guides') {
                $pages['category'] = 3;
            }
            elseif ($_GET['category'] == 'mods') {
                $pages['category'] = 4;
            }
            elseif ($_GET['category'] == 'other') {
                $pages['category'] = 5;
            }
            elseif ($_GET['category'] == 'cheats-codes') {
                $pages['category'] = 7;
            }
            elseif ($_GET['category'] == 'cybersport') {
                $pages['category'] = 8;
            }
            elseif ($_GET['category'] == 'interview') {
                $pages['category'] = 9;
            }
            else {
                $pages['category'] = 'all';
            }  
        }
        else {
            $pages['category'] = 'all';
        }
Правильно?

А как быть, если мы не знаем заведомо какие данные будут переданы (текст, цифры), но обработать их нужно?

2.3 Чтобы проверить, не передается ли массив там, где должна быть строка, проверяем так:
Код:
if (is_array($list))
{
    // пришел массив вместо строки - возвращаем ошибку
}
else
{
    // пришла строка, обрабатываем запрос
}
Правильно?

Нужно ли делать какие-либо другие проверки?

3. Защита выводимых данных

Так как пользователи могут передать в базу HTML код или JS код, данные надо "обезвреживать" при выводе (как мне объяснили, именно при выводе, а не вводе).

Вопросов появляется два: 1) какие именно символы необходимо преобразовывать? Знаки < >, и все? И какой способ наилучший?

Я делаю так:
Код:
$Comment = str_replace(array("<", ">"), array("&lt;", "&gt;"), $Comment);
Это наилучший способ?

4. Защита от спам-запросов

Например от постоянных переборов паролей, или постоянных запросов в поиск (чем можно сильно загрузить сервер), этой темой пока не интересовался - какие можете посоветовать способы (желательно сразу с примерами) защиты в этом случае?

P.S.

Есть ли другие области, в которых необходимо защищать сайт? Например как правильно обрабатывать принимаемые файлы, или что-либо еще в этом плане.
 

Фанат

oncle terrible
Команда форума
1. Для приведенного примера этого достаточно. Но не работает если нужно подставить в запрос имя колонки- например отсортировать по выбранному пользователем полю.
2. Это ерунда, к безопасности отношения не имеет. Да ошибок быть не должно, но если и появится, то никакой дыры в безопасности она не откроет.
Другое дело, что на боевом сервере вывод ошибок на экран должен быть запрещен. Но это относится ко всем ошибкам вообще, а не конкретно только к этой.
2.1 Фильтровать вообще ничего не нужно. Если так хочется проверять входящие данные - их нужно валидировать и сообщать об ошибке. Делать из массива число не имеет ни малейшего смысла.
2.2 Открой для себя массивы. if (isset($_GET['category']) && isset($categories[$_GET['category']]) $pages['category'] = $categories[$_GET['category']]; вместо той простыни кода что ты тут накатал.
Если не знаем заранее, то и не паримся. Любая валидация - она для удобства а не для безопасности.
2.3 все верно.
3. Нет, недостаточно. Если вывод идет в яваскрипт, то эти скобочки вообще не о чем. Весь вывод - через шаблонизатор с автоматическим и контекстным искейпингом. Например Twig.
4. Не заморачивайся пока.
P.S. http://phpfaq.ru/tech/safety http://phpfaq.ru/tech/hashing
 
Последнее редактирование:

Vladson

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

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