#php #mysql #security #dynamic
#php #mysql #Безопасность #динамический
Вопрос:
Я пишу динамический сайт, работающий на PHP и MySQL (для запуска на сервере WAMP). В настоящее время меня беспокоит безопасность сайта, однако на нем не сохраняется никакой пользовательский ввод, а затем выводится для любых пользователей (кроме администраторов), поэтому я не очень беспокоюсь о XSS. Мои основные опасения связаны с атаками SQL-инъекций и защитой портала входа администратора от rainbow tables / перебора.
1) Защищает ли использование mysql_real_escape_string в сочетании со sprintf() от внедрения SQL? например,
$thing = mysql_real_escape_string($_REQUEST['thing'])
$query = sprintf("SELECT * FROM table WHERE thing='%s'", $thing);
$result = mysql_query($query);
Достаточно ли это безопасно? Конечно, ни одна система не является абсолютно безопасной, но я знаю, что подготовленные инструкции должны быть лучшим способом защиты от внедрения SQL. Однако, если мой код «достаточно безопасен», то я не вижу причин вносить изменения заново. Я где-то читал, что mysql_query по умолчанию разрешает только один запрос MySQL на вызов по соображениям безопасности, это правильно? Если да, то я не вижу, как какие-либо инъекции могут быть выполнены в моем коде, но, пожалуйста, дайте мне знать, если в моей логике здесь есть недостаток.
2) Я пишу портал администратора для сайта, чтобы его владельцы могли легко и удобно управлять базой данных MySQL на веб-сайте (из HTML-файла для входа в систему, на который нигде на сайте нет ссылок). Меня беспокоит безопасность процесса входа в систему, который состоит из двух страниц. Во-первых, сбор информации для входа пользователя:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title>Admin Portal</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="robots" content="noindex, nofollow">
<link rel="stylesheet" type="text/css" href="http://www.anotherdomain.com/my.css">
<script type="text/javascript" src="http://www.anotherdomain.com/my.js"></script>
</head>
<form method="post" action="admin/login.php">
<table align="center">
<tr><th>Admin Login Form</th></tr>
<tr><td>Name</td><td><input type="text" name="Name" size="30" onKeyPress="return aJSFunctionToStopEnterKeyFromWorking(event)"></td></tr>
<tr><td>Password</td><td><input type="password" name="Password" size="30" onKeyPress="return aJSFunctionToStopEnterKeyFromWorking(event)"></td></tr>
<tr><td></td><td><input type="reset" value="Clear Form"> <input type="submit" value="Login"></td></tr>
</table>
</form>
Во-вторых, сам скрипт входа в систему:
<?php
$inputusername = $_POST['Name'];
$inputpassword = $_POST['Password'];
$username = "a username that is not obvious";
$password = "a password that is at least 10 characters long";
$salt = hash('sha512', "a messed up string with weird characters that I wrote");
$hashword = hash('sha512', $password . $salt);
$inputhashword = hash('sha512', $inputpassword . $salt);
if($username == $inputusername amp;amp; $hashword == $inputhashword) {
session_start();
$_SESSION['valid'] = 1;
header('Location: portal.php');
exit;
}
else {echo "Invalid username or password";}
?>
И затем, после процесса входа в систему, на каждой странице будет указано следующее, чтобы убедиться, что администратор вошел в систему:
<?php
session_start();
if(!$_SESSION['valid']) {header('Location: ../admin.html');}
?>
Portal page goes here
Поскольку новых пользователей не создается, на портале всегда будет только один пользователь. Мне просто интересно, насколько безопасен этот метод входа в систему против таких атак, как rainbow tables и brute forcing? Я предполагаю, что, поскольку я сделал хэш-слово и соль очень большими, они должны быть вполне защищены от подобных атак, даже если имя пользователя было каким-то образом известно.
Мне также интересно, безопасно ли это от перехвата сеанса, поскольку я слышал этот термин, но я мало о чем знаю… Я знаю, что я никогда не использую идентификатор сеанса или что-то в этом роде, поэтому это кажется довольно безопасным.
3) Любые другие проблемы безопасности, о которых я должен знать / подумать?
Я действительно ценю любую помощь, которую я получаю с этим!
Ответ №1:
Другие моменты, о которых стоит подумать:
1. Вы уязвимы для грубой силы
Атака по словарю может взломать ваш пароль. Поскольку подавляющее большинство пользователей имеют небезопасный пароль, это всего лишь вопрос времени. Используйте captcha или регистрируйте недопустимые записи. Или добавьте некоторую задержку при неправильном вводе пароля.
Как полковник . Шрапнель сказал, что таблица rainbow вас не беспокоит, потому что они используются, когда у кого-то есть куча хэшей и он хочет их взломать. Соль используется для получения некоторой защиты от таблицы rainbow, и это не ваш случай.
2. Вы отправляете пароли открытым текстом
Если кто-то прослушает ваш логин (например, Wi-Fi), вы обречены. Есть несколько библиотек javascript, которые могут шифровать что угодно, используя открытые ключи. Если вы не хотите использовать SSL, зашифруйте логин / пароль, отправьте на сервер, расшифруйте с помощью закрытого ключа, и вы в большей безопасности.
3. Рассмотрите возможность использования подготовленных инструкций в MySQL
Использование подготовленных инструкций помогает избежать внедрения SQL, поскольку оно может безопасно выполняться даже при вредоносном вводе:
$dbc = new mysqli("mysql_server_ip", "mysqluser", "mysqlpass", "dbname");
$statement = $db_connection->prepare("SELECT * FROM table WHERE thing='?'");
$statement->bind_param("i", $thing);
$statement->execute();
4. Не передавайте проверку на стороне клиента
В вашей форме входа в систему вы передаете функцию javascript, препятствующую функционированию клавиши Enter. Что, если я отключу Javascript? Вы могли бы использовать скрытое поле (например, <тип ввода=’hidden’ name=’FormIsValid’ value=’0′ >), использовать вашу функцию для предотвращения нажатия клавиши Enter И использовать функцию onSubmit() для изменения FormIsValid на 1 перед отправкой формы. На вашем сервере проверьте FormIsValid.
5. Вы уязвимы для перехвата сеанса
Ваш сеанс сохраняется в файле cookie, по умолчанию именуемом PHPSESSID. Если злоумышленник сможет получить этот файл cookie, он может отправить его на ваш сервер и украсть ваш сеанс. Чтобы предотвратить это, вы можете сохранить IP-адрес пользователя и пользовательский агент в сеансе и сравнивать значение, полученное из сеанса при каждом запросе. Если значения не совпадают, возможно, изменился IP-адрес пользователя или сеанс был взломан.
6. Вы можете быть уязвимы для фиксации сеанса
Как указано выше, если кто-то убедит вашего администратора получить доступ к какому-либо сайту, и этот сайт отправит запрос на ваш сайт с идентификатором PHPSESSID в запросе, ваш сайт создаст сеанс, обработает логин / пароль и сообщит, что учетные данные неверны. До сих пор неплохо.
Позже ваш администратор войдет в ваш портал, сеанс уже существует, логин и пароль совпадают, и сеанс ОБНОВЛЯЕТСЯ. Действительная переменная сейчас равна 1.
Как только переменная обновляется, злоумышленник получает полный доступ к вашему порталу, поскольку он знает PHPSESSID, ваш сайт не предотвращает перехват сеанса или фиксацию сеанса.
Чтобы избежать фиксации сеанса и перехвата, смотрите # 5.
Комментарии:
1. Несколько вещей. Какая разница, указаны ли пароли в виде обычного текста, если идентификатор сеанса (который является реальным токеном аутентификации) отправляется в виде открытого текста. Ваше решение по-прежнему является нарушением OWASP A9. Какая разница, как называются файлы cookie, это не влияет на фиксацию сеанса. Чтобы остановить фиксацию сеанса, вы просто устанавливаете
session.use_only_cookies=1
в своем php.ini.2. Кроме того, вы полностью пропустили уязвимость обхода аутентификации, которая намного серьезнее, чем все, что вы перечислили.
3. @Rook Я сфокусировал только скрипт аутентификации, а не все другие скрипты в сеансе администратора.
4. @Rook, спасибо, что затронули session.use_only_cookies = 1, я совершенно забыл об этом и теперь добавил в свой session.class.php (:
Ответ №2:
1) Защищает ли использование mysql_real_escape_string в сочетании с sprintf() от внедрения SQL?
При условии, что 1) вы применяете эту функцию только к строкам и 2) установлено правильное использование кодировки mysql_set_charset()
.
Для чисел вы могли бы просто использовать %d
Я где-то читал, что mysql_query по умолчанию разрешает только один запрос MySQL на вызов по соображениям безопасности, это правильно?
Вы правы. Не так много для безопасности, но, скорее всего, по дизайну.
Если да, то я не вижу, как какие-либо инъекции могут быть выполнены в моем коде, но, пожалуйста, дайте мне знать, если в моей логике здесь есть недостаток.
Вы ошибаетесь. SQL injection означает внедрение SQL-кода в ваш запрос, а не просто отдельного запроса «bobby drop tables».
Мне просто интересно, насколько безопасен этот метод входа в систему против таких атак, как rainbow tables и brute forcing?
Rainbow tables здесь ни при чем, в то время как грубое принуждение все еще представляет опасность.
Хотя я не думаю, что это имеет большое значение. Не больше, чем отправка пароля в виде обычного текста.
Я предполагаю, что, поскольку я сделал хэш-слово и соль очень большими, это должно быть вполне безопасно
Здесь интересный момент.
На самом деле, вся эта путаница с хэшированием / пересаливанием здесь совершенно бесполезна. Это не более безопасно, чем простое сравнение паролей.
Мне также интересно, безопасно ли это от перехвата сеанса,
всегда есть такая возможность. Если вы так сильно обеспокоены, используйте SSL-соединение, как это делает Google mail.
так что я не очень беспокоюсь о XSS.
Это довольно ложное ощущение.
такая простая, как echo "Requested article: ".$_GET['id']'
вещь, уже уязвима.
Комментарии:
1. О, неважно. Теперь я понимаю, что вы имеете в виду. Неважно. По сути, вы говорите, что он ошибается, предполагая, что инъекции невозможны, поскольку MySQL разрешает только один запрос на вызов. Я тебя понимаю…
Ответ №3:
Похоже, что другие разобрали это отдельно. Но мне нужно добавить еще один:
Обход аутентификации:
<?php
session_start();
if(!$_SESSION['valid']) {header('Location: ../admin.html');}
?>
Когда вы выполняете a, header("location: ...")
скрипт все еще выполняется, вам все равно нужно exit
или die()
. Таким образом, фактически с помощью этого фрагмента кода я знаю, что все ваши страницы могут быть доступны пользователю, не прошедшему проверку подлинности.
Ответ №4:
Другие улучшения:
Проверьте тип ваших параметров, прежде чем использовать их для чего-либо. (За исключением текстового поиска. Для этого требуется немного больше). Пропущенное значение может вызвать ошибку SQL, на которой злоумышленники могут извлечь уроки 😉
Поместите токен защиты от csrf на свою страницу входа в систему и переводите в спящий режим после неудачного входа в систему, чтобы предотвратить атаки методом грубой силы.
Войдите в систему через https. Через http вы отправляете четкие пароли через сеть. Идеальный сценарий атаки «человек посередине» (но это довольно сложно сделать :).
Проверьте правильность кодировки ввода. Есть несколько атак UTF-7, в которых используются японские многобайтовые символы, у которых одна кавычка в качестве второго байта. (Это может привести к разрыву mysql_real_escape_string) Очень сложная штука.
Используйте подготовленные инструкции