Не эксперт по безопасности. Но кое-что знаю.
Я занимался аудитом кода многих проектов...
... и практически всегда встречал всё те же ошибки.
$_SERVER['HTTP_X_FORWARDED_FOR']
и т.д.)Фильтровать = убедиться, что данные верны.
Входные данные не валидны пока не доказано обратное.
$email = filter_var($email, FILTER_VALIDATE_EMAIL);
if ($email === false) {
// email не торт...
}
// всё OK
или используйте надёжные библиотеки и фреймворки
Сделать так, чтобы спецсимволы вели себя как нормальные символы.
Обычно префиксированием других спецсимволов.
На каждый выход свои правила экранирования.
На страницу вставляется скрипт, который запсукается в браузере пользователя.
Встречалось в большинстве проектов, с которыми я работал.
...
<div>
<?= $_GET['query'] ?>
</div>
...
Экранируй!
Если нужет только текст.
htmlspecialchars($content, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
Если нужен именно HTML.
HTMLPurifier (http://htmlpurifier.org/)
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
$clean_html = $purifier->purify($dirty_html);
Они могут вам понадобится в исходном виде. К тому же, базе доверять нельзя.
Сторонний сайт может отправить формы на ваш сайт от имени пользователя.
Использовать токены CSRF, использовать TLS/SSL.
<img src="/logout" />
Использование $_REQUEST
- то же самое.
Выполнение произвольного SQL в БД проекта.
$email = $_POST['email'];
query("SELECT *
FROM user
WHERE email = '$email';");
' OR 1
UNION SELECT 1,'',3,4,5 INTO OUTFILE '1.php' --%20
UNION SELECT 1,LOAD_FILE('config.php'),3,4,5 --%20
Экранируйте запросы.
addslashes()
mysql_escape_string()
mysql_real_escape_string()
Есть и в PDO и нативных драйверах. Для PDO:
$stmt = $db->prepare("SELECT * FROM user WHERE email = :email");
$stmt->bindValue(':email', $email);
$user = $stmt->fetch();
Используйте белый список.
$allowedTables = ['user_comments', 'post_comments'];
if (!in_array($table), $allowedTables, true) {
return false;
}
// делаем запрос
Возможность загрузить и запустить код.
Возможность выполнить произвольный код.
eval($_GET['query']);
Не использовать eval() или использовать после проверки по белому списку.
Запускайте PHP с минимально возможными правами
require $_GET['type'] . '.php';
Обманом заставить пользователя кликнуть на что-то на стороннем сайте.
iframe + opactity: 0
Не особо относится к PHP, но довольно серьёзно.
Запретить запихивать сайт в фреймы через RFC 7034:
header('X-Frame-Options: DENY');
// или
header('X-Frame-Options: SAMEORIGIN');
или через JavaScript:
if (window.top !== window.self) {
document.write = "";
window.top.location = window.self.location;
setTimeout(function () {
document.body.innerHTML = '';
}, 1);
window.self.onload = function (evt) {
document.body.innerHTML = '';
};
}
Храните хэш.
Даже с солью.
Полный перебор пароля из 8 символов, SHA-256 занимает...
3.5 дня на одной GPU 2011 года
На крутой GPU 2015 года это будет уже 20 часов
итерации key derivation function = 2^cost
12+ - безопасное значение. Yii использует 13.
Cost = 13 → ~28 хэшей в сек. на Nvidia GTX Titan X ($1900)
28 * 60 * 60 * 24 = 2419200 хэшей в день
6 символьный пароль, буквы в нижнем регистре = 308915776 комбинаций
308915776 / 2419200 = 127 дней для перебора одного пароля
21 день с 6-ю видеокартами. Стоит это более ~15000$
Добавим в пароль из 6 символов цифры и стоить взлом за 21 день будет уже более ~81000$
GPU становятся все лучше и всё дешевле.
AMD R380X даёт 14 хешей bcrypt с cost=13 в секунду и стоит около $200.
Если вы знаете, что хэши утекли:
У вас будет больше времени среагировать на утечку.
Дать пользователю заранее известный ID сессии.
Используйте только куки. В php.ini:
session.use_cookies = 1
session.use_only_cookies = 1
session_cookie_httponly = 1
Регенерируйте ID сессии при помощи session_regenerate_id(true)
после логина или смены прав.
Да, такое бывает.
Сначала запрещайте всё, потом уже разрешайте.
Используются для токенов, кодов сброса, генерируемых паролей, UUID и др.
Случайные числа могут генерироваться предсказуемо или могут повторяться если источник не достаточно хорош.
Токены, коды сброса, генерируемые пароли
Использовать нормальные источники случайных чисел
Проводите тесты
Держите про запас отменного админа...
Нельзя сделать приложение безопасным один раз и навсегда.
Идеально, если в команде есть кто-то, кто знаком с темой. Используйте VCS и делайте code review.
Планируйте заранее.
target="_blank"
не безопасен