У меня есть веб-страница login.html, которая позволяет пользователю вводить имя пользователя и пароль. Когда он нажимает на submit, я собираю введенное значение с помощью Javascript, а затем делаю AJAX POST Call в php-файл и отправляю имя пользователя и пароль.
Меня беспокоит, что это безопасный способ отправки имени пользователя и пароля? Если нет, как я могу защитить эту транзакцию от отправки данных из html-файла на php, запускающей бэкэнд?
Затем файл php подключается к MySql Db и проверяет, выходит ли пользователь, и если пароль правильный. Если да, он просто отправляет действительный текст обратно на вызовы ajax функции javascript, если не я определяю, что это недопустимый пользователь?
Я не совсем доволен этой логикой? Есть ли лучший способ реализовать этот процесс? Поскольку я помещаю свой код в производство, я хочу обеспечить его как можно больше.
Приведенный ниже код работает отлично, мне просто нужны советы для его защиты.
login.html
<div> <h3>Login information</h3> <input type="text" name="user" id="usrnm" placeholder="Username/Email"> <input type="password" name="pswdlogin" id="pswdlogin" placeholder="Password"> <input type="checkbox" name="keepmeloggedin" id="keepmeloggedin" value="1" data-mini="true"> <input type="submit" data-inline="false" onclick="logmein()" value="Log in"> <div id="loginstatus"> </div> </div>
logmein.js
function logmein() { var usrnm = document.getElementById("usrnm").value; var pswdlogin = document.getElementById("pswdlogin").value; $.post("http://xyz/mobile/php/logmein.php", { usrnm: usrnm, pswdlogin: pswdlogin }, function(data, status) { if (data == 'Valid') { window.open("http://xyz/mobile/home.html?email=" + usrnm + "", "_parent"); } else { alert(data); document.getElementById("loginstatus").innerHTML = data; } }); }
logmein.php
<?php $usrnm_original = $_POST['usrnm']; $pswdlogin_original = $_POST['pswdlogin']; $con = mysqli_connect("localhost", "cSDEqLj", "4GFU7vT", "dbname", "3306"); if (mysqli_connect_errno()) { echo "Failed to connect to MySQL: " . mysqli_connect_error(); } mysqli_select_db($con, "dbname"); $usrnm = mysqli_real_escape_string($con, $usrnm_original); $pswdlogin = mysqli_real_escape_string($con, $pswdlogin_original); $result = mysqli_query($con, "SELECT * FROM registration WHERE email = '" . $usrnm . "' AND password='" . $pswdlogin . "' "); $rows = mysqli_num_rows($result); if ($rows == 1) { echo "Valid"; } else { echo "In Valid Credentials Entered"; } mysqli_close($con); ?>
Это действительно относится к codereview.stackexchange.com, но я все равно дам ему шанс.
Во-первых, я бы добавил к вашей форме токен csrf, чтобы остановить эти типы атак.
//the most simple type of csrf token if (!isset($_SESSION['token'])): $token = md5(uniqid(rand(), TRUE)); $_SESSION['token'] = $token; else: $token = $_SESSION['token']; endif;
Затем в вашей форме введите скрытое поле ввода:
<input type="hidden" name="token" id="token" value="<?php echo $token; ?>"/>
Затем в вашем ajax добавьте токен.
var usrnm = $('#usrnm').val(); var pswdlogin = $('#pswdlogin').val(); var token = $('#token').val(); { usrnm: usrnm, pswdlogin: pswdlogin, token: token }
Затем в вашем php, давайте остановим неопределенные ошибки индекса при доступе к этой странице напрямую.
$usrnm_original = isset($_POST['usrnm'])?$_POST['usrnm']:false; $pswdlogin_original = isset($_POST['pswdlogin'])?$_POST['pswdlogin']:false; $token = isset($_POST['token'])$_POST['token']:false;
Затем нам нужно проверить, прошел ли токен, который был принят, как наш токен
if(!$_SESSION['token'] == $token): die('CSRF Attacks are not allowed.'); endif;
Затем нам нужно прекратить использование mysqli_query
при принятии пользовательских данных, даже если они дезинфицируются с помощью mysqli_real_escape_string
и вместо этого используют prepared
инструкции. Кроме того, код процедурного стиля заставляет меня плакать, поэтому мы это изменим. Кроме того, давайте вернем массив со статусом и сообщением, так что легче обрабатывать сообщения об ошибках и успехах.
$ret = array(); $mysqli = new mysqli("localhost", "cSDEqLj", "4GFU7vT", "dbname"); if($sql = $mysqli->prepare('SELECT * FROM registration WHERE email = ? and password = ?')): $sql->bind_param('ss', $usrnm_original, $pswd_original); if($sql->execute()): $sql->fetch(); if($sql->num_rows > 0): $ret['status'] = true; $ret['msg'] = 'You have successfully logged in! Redirecting you now'; else: $ret['status'] = false; $ret['msg'] = 'The credentials supplied were incorrect. Please try again'; endif; endif; $sql->close(); return json_encode($ret); endif;
Теперь нам нужно изменить вашу функцию post.
$.post("http://xyz/mobile/php/logmein.php", { usrnm: usrnm, pswdlogin: pswdlogin, token:token }, function(data) { if (data.status == true) { window.open("http://xyz/mobile/home.html?email=" + usrnm + "", "_parent"); } else { alert(data.msg); $('#loginstatus').text(data.msg); } }, 'json');
Наконец, и самое главное, у вас есть простой текстовый метод использования паролей, что не имеет смысла с точки зрения безопасности. Это как раз то, как вас взломали. Вместо этого вы должны использовать хотя бы sha256
хэширования sha256
. Измените, как пароли хранятся в базе данных для использования sha256
затем выполните сравнение путем передачи этого в селектор SQL, например:
$pswdlogin_original = isset($_POST['pswdlogin'])? hash('sha256', $_POST['pswdlogin']):false;
И при сохранении в базе данных пароль будет выглядеть, например, как fcec91509759ad995c2cd14bcb26b2720993faf61c29d379b270d442d92290eb
.
Мой ответ был для ясности, но на самом деле вы не должны даже изобретать вещи. Существует множество приложений и фреймворков, которые затратили немало времени на обеспечение безопасности своих систем аутентификации. Я бы рекомендовал изучить все эти вопросы, так как они помогут вам создать основные навыки программирования и научить фундаментальным методам ООП
Надеюсь, это было полезно.
Прежде всего, если вам нужна «верхняя» защита, вы должны использовать HTTPS с действующим сертификатом, иначе любой злоумышленник сможет создать человека в средней атаке и перехватить ваши данные (я думаю, это ваша главная проблема). Выполнение HTTPS на странице входа в систему не имеет смысла, поскольку тот же самый атакующий может совершить атаку с захватом сеанса и выдавать себя за других пользователей, не зная пароля.
Имейте в виду, что нет разницы в использовании AJAX или HTML-формы, данные отправляются по проводке одинаково.
Если вы не хотите тратить больше ресурсов (как правило, HTTPS cerficates стоит денег), вы можете пойти «не так хорошо»: передать хешированную версию пароля , но это тоже имеет свои недостатки (если вы не используете хэш на стороне сервера, тогда пароль становится самим хешем …)
Как советовали, не пытайтесь изобретать колесо, попробуйте использовать хорошо известную инфраструктуру, например Laravel, или одну меньшую, такую как Slim или Silex, может быть проще перенести ваш код на них.
В конце вы должны спросить себя, каков худший вариант, если какой-либо пользователь получает доступ к другой учетной записи? Если вы развертываете тривиальное приложение без личных данных, возможно, ваше текущее решение достаточно хорошо, с другой стороны, если вы имеете дело с конфиденциальной информацией, вы должны уделять большое внимание обеспечению безопасности вашего сайта.
Дальнейшее чтение: