Ниже приведена десятка уязвимостей безопасности, которые могут скрываться в вашем коде PHP.
1. Непроверенные параметры
Самое главное, выключить
register_globals
Этот параметр конфигурации по умолчанию отключен в PHP 4.2.0 и более поздних версиях. Доступ к значениям из URL-адресов, форм и файлов cookie через суперглобальные массивы
$_GET
$_POST
$_COOKIE
Прежде чем использовать значения из суперглобальных массивов, проверьте их, чтобы убедиться, что они не содержат неожиданного ввода. Если вы знаете, какой тип значения вы ожидаете, убедитесь, что полученное значение соответствует ожидаемому формату. Например, если вы ожидаете почтовый индекс США, убедитесь, что ваше значение составляет либо пять цифр, либо пять цифр, дефис и еще четыре цифры (ZIP + 4). Часто регулярные выражения являются самым простым способом проверки данных:
if (preg_match('/^\d{5}(-\d{4})?$/',$_GET['zip'])) {
$zip = $_GET['zip'];
} else {
die('Invalid ZIP Code format.');
}
Если вы ожидаете получить данные в файле cookie или в скрытом поле формы, которое вы ранее отправили клиенту, убедитесь, что они не были подделаны, отправив хэш данных и секретное слово вместе с данными , Поместите хэш в скрытое поле формы (или в файл cookie) вместе с данными. Когда вы получите данные и хеш, повторно хешируйте данные и убедитесь, что новый хеш совпадает со старым:
// sending the cookie
$secret_word = 'gargamel';
$id = 123745323;
$hash = md5($secret_word.$id);
setcookie('id',$id.'-'.$hash);
// receiving and verifying the cookie
list($cookie_id,$cookie_hash) = explode('-',$_COOKIE['id']);
if (md5($secret_word.$cookie_id) == $cookie_hash) {
$id = $cookie_id;
} else {
die('Invalid cookie.');
}
Если пользователь изменил значение идентификатора в куки, хэши не будут совпадать. Успех этого метода, очевидно, зависит от сохранения
$secret_word
секрет, поэтому поместите его в файл, который никто не может прочитать, и периодически меняйте его. (Но помните, что если вы измените его, старые хэши, которые могут лежать в файлах cookie, больше не будут действительны.)
Смотрите также:
- Руководство по PHP: Использование регистров Globals
- Поваренная книга PHP: рецепт 9.7 («Защита обработки форм PHP»), рецепт 14.3 («Проверка данных с помощью хэшей»)
2. Сломанный контроль доступа
Вместо использования собственного решения для контроля доступа используйте модули PEAR.
Auth
выполняет проверку подлинности на основе файлов cookie для вас и
Auth_HTTP
выполняет аутентификацию на основе браузера.
Смотрите также:
3. Сломанный аккаунт и управление сессиями
Используйте встроенные функции управления сессиями PHP для безопасного, стандартизированного управления сессиями. Однако, будьте осторожны, как ваш сервер настроен для хранения информации о сеансе. Например, если содержимое сеанса хранится в виде общедоступных файлов в / tmp, то любой пользователь, который входит на сервер, может видеть содержимое всех сеансов. Храните сеансы в базе данных или в той части файловой системы, к которой имеют доступ только доверенные пользователи.
Чтобы запретить анализаторам сети идентификаторы сеансов, трафик, специфичный для сеанса, должен отправляться через SSL. Вам не нужно делать ничего особенного для PHP, когда вы используете соединение SSL, но вам нужно специально настроить свой веб-сервер.
Смотрите также:
- Руководство по PHP: функции обработки сессий
- Поваренная книга PHP: Рецепт 8.5 («Использование отслеживания сеансов»), Рецепт 8.6 («Хранение сеансов в базе данных»)
4. Недостатки межсайтового скриптинга (XSS)
Никогда не отображайте информацию, поступающую извне вашей программы, без предварительной фильтрации. Отфильтруйте переменные, прежде чем включать их в скрытые поля формы, в строки запроса или просто вывод страницы.
PHP предоставляет вам множество инструментов для фильтрации ненадежных данных:
htmlspecialchars()
витки
& > " <
в их эквиваленты HTML-сущности, а также может преобразовывать одинарные кавычки, передавая
ENT_QUOTES
в качестве второго аргумента.
strtr()
фильтрует любые символы, которые вы хотите. Проходят
strtr()
массив символов и их замены. Изменить
(
и
)
в их эквиваленты сущности, что рекомендуется для предотвращения атак XSS, выполните:
$safer = strtr($untrusted, array('(' => '(', ')' => ')'));
strip_tags()
удаляет теги HTML и PHP из строки.
utf8_decode()
преобразует символы ISO-8859-1 в строку, кодированную кодировкой Unicode UTF-8, в однобайтовые символы ASCII. Иногда злоумышленники, использующие межсайтовый скриптинг, пытаются скрыть свои атаки в кодировке Unicode. Ты можешь использовать
utf8_decode()
снять эту кодировку.
Смотрите также:
- Руководство по PHP: htmlspecialchars () , strtr () , strip_tags () , utf8_decode ()
- Поваренная книга PHP: рецепт 8.8 («Построение строки запроса GET»), рецепт 9.8 («Избегание управляющих символов из пользовательских данных»)
5. Переполнение буфера
Вы не можете распределять память во время выполнения в PHP, и они не являются указателями, как в C, поэтому ваш PHP-код, каким бы небрежным он ни был, не будет иметь переполнения буфера. Однако вы должны следить за переполнением буфера в самом PHP (и его расширениях). Подпишитесь на список рассылки php-announce, чтобы быть в курсе патчей и новых выпусков.
Смотрите также:
- Списки рассылки PHP: http://www.php.net/mailing-lists.php
6. Командные недостатки при внедрении
Недостатки межсайтового скриптинга возникают, когда вы отображаете нефильтрованный, неэкранированный вредоносный контент в браузере пользователя. Недостатки внедрения команд возникают при передаче нефильтрованных, неэкранированных вредоносных команд во внешний процесс или базу данных. Чтобы избежать ошибок при внедрении команд, в дополнение к проверке ввода всегда экранируйте пользовательский ввод перед передачей его во внешний процесс или базу данных.
Если вы передаете пользовательский ввод в оболочку (с помощью команды вроде)
exec()
system()
или оператор backtick), сначала спросите себя, действительно ли вам это нужно. Большинство файловых операций можно выполнять с помощью встроенных функций PHP. Если вам абсолютно необходимо запустить внешнюю программу, имя или аргументы которой поступают из ненадежного ввода, экранируйте имена программ с помощью:
escapeshellcmd()
и аргументы с:
escapeshellarg()
Перед выполнением внешней программы или открытием внешнего файла вы также должны канонизировать его путь:
realpath()
Это расширяет все символические ссылки, перевод:
.
(Текущий каталог)
..
(родительский каталог) и удаляет дубликаты разделителей каталогов. После того, как имя пути канонизировано, вы можете проверить его на соответствие определенным критериям, таким как нахождение под корнем документа веб-сервера или в домашнем каталоге пользователя. Если вы передаете пользовательский ввод в запрос SQL, экранируйте ввод с помощью:
addslashes()
прежде чем положить его в запрос. Если вы используете MySQL, экранируйте строки с помощью:
mysql_real_escape_string()
or
mysql_escape_string()
для версий PHP до 4.3.0). Если вы используете уровень абстракции базы данных PEAR DB, вы можете использовать метод DB :: quote () или использовать заполнитель запроса, например:
?
который автоматически экранирует значение, которое заменяет заполнитель.
Смотрите также:
- PHP Manual: escapeshellcmd(), escapeshellarg(), realpath(), addslashes(), mysql_real_escape_string(), mysql_escape_string()
- PEAR Package: DB, DB Documentation
- PHP Cookbook: Recipe 18.20 (”Escaping Shell Metacharacters”), Recipe 10.9 (”Escaping Quotes”)
7. Error Handling Problems
If users (and attackers) can see the raw error messages returned from PHP, your database, or external programs, they can make educated guesses about how your system is organized and what software you use. These educated guesses make it easier for attackers to break into your system. Error messages shouldn’t contain any descriptive system information. Tell PHP to put error messages in your server’s error log instead of displaying them to a user with these configuration directives:
log_errors = On
display_errors = Off
See Also:
- PHP Manual: Error Handling and Logging Functions
- PHP Cookbook: Recipe 8.14 (”Hiding Error Messages from Users”)
8. Insecure Use of Cryptography
The mcrypt extension provides a standardized interface to many popular cryptographic algorithms. Use mcrypt
instead of rolling your own encryption scheme. Also, be careful about where (if anywhere) you store encryption keys. The strongest algorithm in the world is pointless if an attacker can easily obtain a key for decryption. If you need to store keys at all, store them apart from encrypted data. Better yet, don’t store the keys and prompt users to enter them when something needs to be decrypted. (Of course, if you’re prompting a user over the web for sensitive information like an encryption key, that prompt and the user’s reply should be passed over SSL.)
See Also:
- PHP Manual: Mcrypt Encryption Functions
- PHP Cookbook: Recipe 14.7 (”Encrypting and Decrypting Data”)
9. Remote Administration Flaws
When possible, run remote administration tools over an SSL connection to prevent sniffing of passwords and content. If you’ve installed third-party software that has a remote administration component, change the default administrative user names and passwords. Change the default administrative URL as well, if possible. Running administrative tools on a different web server than the public web server that the administrative tool administrates can be a good idea as well.
10. Web and Application Server Misconfiguration
Keep on top of PHP patches and security problems by subscribing to the php-announce mailing list. Stay away from the automatic PHP source display handler (
AddType application/x-httpd-php-source .phps
), since it lets attackers look at your code. Of the two sample php.ini samples that ship with PHP php.ini-dist and php.ini-recommended use php.ini-recommended as a base for your site configuration.