Правила безопасности

  • Всегда проверяйте данные от пользователя и преобразуйте из в минимальную нужную вам величину, а так же используйте для получения данных ф-ии движка (Get(), Post())

    Функции Get() и Post() уже имеют некоторую встроенную защиту, так они убирают XSS инъекции и преобразуют Html вставки, но всегда нужно понимать, что главной защитой является ум и профессионализм программиста.
    Большинство ошибок появляется именно из-за пренебрежения должного отношения к входным данным, потому соблюдайте правило: Всегда проверяйте данные от пользователя и преобразуйте из в минимальную нужную вам величину Давайте я приведу несколько неправильных примеров получения номера страницы, а в конце покажу корректный.
    Не правильные примеры

                        $page = Get('p', 1); // Неверно - Можно передать строку
                        $page = intval(Get('p', 1)); // Неверно - возможны отрицательные числа
                        $page = abs(intval(Get('p', 1))); // Неверно - возможно получить 0, а мы считает что страницы от 1
    
                        // Верный вариант выглядит следущим образом:
                        $page = abs(intval(Get('p'))); // Всегда вернёт положительное число
                        $page = $page > 0 ? $page : 1; // Если 0 то показывать первую страницу
                    

    Ещё один вариант неправильной проверки:
                        if ($n != (int)$n)
                        {
                            // Если передать вначале число то всё пройдёт
                            // Пример: $n = "123' AND BENCHMARK(SIN(1), 100000000000000) --"
                        }
                    
    Правильным вариантом всегда будет задать себе вопрос: "Каковы возможные значения этой переменной?" и после этого накладывать ограничения.
    В пример с номером страницы, если бы сразу себе сказали, что номер страницы это обязательно число которое должно быть больше ноля, то выставили бы нужные ограничения.

  • Измените стандартные названия лог-файлов и лог-папок

    При установке движка, всегда следует изменить стандартные пути для записи логов, а так же очень не плохо сделать их недоступными из вне (например при запросах через браузер). Если этого не сделать, то мы рискуем что злоумышленник иследовав возникающие ошибки и узнав структуру сайта найдёт уязвимое место.

    Не выключайте логирование ошибок, помните: Используйте мониторинг — взломать не наследив — не просто.
  • Не выводите ошибки на экран на Production-сервере

    Показ ошибок плохо сказывается не только на имидже сайта, но и открывает внутренние механизмы сайта стороннему глазу, причём те механизмы которые работаю некорректно.
    Возможно не плохой практикой будет зайти и переписать компонент 500 под свой дизайн, предоставив пользователю возможность дальнейших действий Компонент 500 показывает сообщение о внутренней ошибке пользователю сайта

  • Давайте всему и всем минимально возможные права

    Очень хорошей привычкой будет раздавать всем наименее возможные права, будть то скрипты, пользоватли mysql и пр.
    Приведу ряд простых примеров:

    1. Минимальные права на mysql пользователя / разделение доступов

      Пусть у нас есть 2 сайта, на одном осуществляются платёжные операции (payment.example.com), а на другом вывод информации из той БД (example.com), тогда граммотным решением будет для сайта который занимается только выводом создать индивидуального mysql пользователя, ограничив его права только на запросы SELECT тем самым даже если например программист на example.com ошибётся, то он не навредит базе на payment.example.com Дополнительным плюсом будет например отдельная статистика запросов с сайтов payment.example.com и example.com, что позволит оценить нагрузку на БД от каждого сайта например.
    2. Доступ к файлам и папкам Пусть Вы написали ошибочный код, который складывает кеш файлы вместо папки tmp в папку tpl и не протестив его должным обзом запустили на сервер, однако если Вы выставили права на запись только в папку tmp, то Ваша папка tpl никогда не запусорится этим хламом и более того Вы еще при первой бы узнате что нет прав на запись в эту папку и быстрее отловите свою ошибку

    Можно привести достаточно много примеров, но всё это следствие одного простого правила: Всегда давайте минимально возможные права

  • Не храните пароли в открытом виде в БД

    Сохраняйте в БД минимально нужную для проверки информацию, в случае с паролями Вам не нужен сам пароль, будет достаточно иметь только хеш на него.
    Т.е. алгорим действий вашего сайта будет таким: 1) При регистрации сохранять логин и хеш_на_пароль сгеренированный по какому-то алгоритму.
    2) При авторизации человек введёт логин и пароль, вы до проверки, используя тот же алгорим преобразуете пароль в хеш т.к. алгоритм тот же самый то и хеш полученный при правильном пароле будет такой же.

                    $pwd        = Post('pwd');
    
                    // Не очень хороший метод т.к. простой md5 легко подбирается по радужным паролям
                    $pwdHash    = md5($pwd);
    
                    // Метод получше т.к. добавлена соль
                    $pwdHash    = md5($pwd . "AnySuperSalt__SecretWord__12345!@#$%");
                
    Но еще лучше, было бы создать уникальную соль для каждого пользователя по его неизменным полям например дата_регистрации пользователя, она достаточно уникальна и при этом подбор соли становится ещё сложнее Стоит отметить, что это правило подходит не только под пароли, но и под другие данные, например для номеров кредитных карт, номеров прикреплённых телефонов и пр. (однако для этих данных я бы еще сохранял начало и конец номера, для отображения пользователю)
  • Для сохранения авторизации используйте сессию, если же используете куки то соблюдайте правила безопасности для кук

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

    А так же используйте флаг httpOnly для кук
  • Проставляйте домен для кук

  • Всегда используйте GET для получения данных но не для действий, для действий используйте только POST

    Предположим мы пренебрегли этим правилом и сделали голосование AJAX-ом по url-у www.example.com/comment?id=1001&action=vote_plus где "id=1001" это id комментария, а "action=vote_plus" - это голосание комментария в плюс.
    Далее человек берёт эту ссылку и размещает её на других сайтах с частым посещением и таким образом накручивает себе голосовалку.
    Или другой пример, человек разместит у себя на сайте на onload старницы AJAX-вызовы:
    www.vk.com/logout, www.gmail.com/logout, www.facebook.com/logout и пр.
    Таким образом попав на эту страницу человек выйдет из всех этих профилей, что является неожиданным поведением.

    Это еще достаточно дружелюбные примеры, вообще принебрежение этим правилом может привести и к более серьёзным проблемам
  • Не доверяйте серверным переменным которые помечены HTTP_... они могут быть поддеданы т.к. передаются от пользователя

    На самом деле список куда шире (HTTP_REFERER, USER_AGENT, mime-type полученных данных и пр.), потому старайтесь проверять достоверность данных и валидировать их
                    header("Location: " . $_SERVER['HTTP_REFFERER']); // Потенциально ошибочный код
                
  • Никогда не полагайтесь на валидацию данных со стороны js, всегда сначала пишите валидацию на сервере а потому как бонус js валидацию

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

  • Оставляйте в прямом доступе минимум файлов

    Если у Вас есть возможность перенести файлы на уровень выше чем дирректория доступная через интернет, то сделав это Вы сущетсво огородите возможность ошибок.
    Хорошим вариантом будет оставить в прямом доступе только файлы .htaccess и /index.php, а всё остальное вынести за пределы прямого доступа.

  • Не давайте пользователю возможность загружать исполняймые программы в прямой доступ

    Представьте что вы решили сделать возможность загрузки аваторок пользователем, однако не поставили должных проверок на тип файла, и человек загрузкил Вам в /upl какой-то php-скрипт delete_all.php после чего он вызывает его по URL (ведь в tmp и upl разрешён прямой доступ) www.example.com/upl/delete_all.php, я думаю результат таких действий понятен.

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

  • При подключении скрипта (например если вы передаете URI в ваш index.php который должен найти и подключить скрипт) проверьте что это безопастное имя

    При несоблюдении этого правила могут может быть например так: /index.php?q=./index.php (зацикливание) или так /index.php?q=../../pass.txt (узнав где пароли, распечатали их)

  • Лучше не пользовать FTP, а заменить его на SFTP

  • Регулярно проверяйтесь на вирусы и снифферы

    Снифферы могут лежать на Вашем компе и следить за FTP коннектами например, после чего отправлять их владельцу вредоносной программы

  • Никогда не выключайте проверки в коде на сервер, assert-ы, trigger_error-ы, исключения и пр.

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