Поэтому некоторое время я экспериментировал с различными подходами AJAX при отправке данных на сервер, которые будут обрабатываться и храниться в базе данных MySQL.
Страница, на которую запрос AJAX попадает на api.php
, использует подготовленные заявления PHP PDO для сохранения данных, поэтому инъекции MySQL на самом деле не являются проблемой, а пароли или данные, которые необходимо зашифровать, также обрабатываются api.php
который api.php
' Что я прошу здесь. Мой вопрос больше связан с тем, как обеспечить безопасность данных при передаче с клиента на сервер.
В настоящее время у меня (для примера входа в систему, который я привел ниже):
login.php
как login.php
и api.php
). api.php
при api.php
при доступе к функциям. api.php
. api.php
(не относится к вопросу). Наконец, мои вопросы:
Я понимаю, что у каждого есть разные подходы к обработке данных своего сайта и транспортировке этих данных. Я также понимаю, что независимо от того, что вы делаете, вы никогда не можете быть защищены на 100%, так как могут быть уязвимости и способы вашей системы, которые вы не можете учитывать. Я ищу отзывы и улучшения в моем общем подходе при отправке данных безопасно, а не в критику конкретного кода ниже, поскольку это всего лишь пример. Но любые конструктивные ответы приветствуются. Спасибо, что нашли время, чтобы прочитать / ответить.
function loginUser() { var process = "loginUser"; var data = $("form").serializeArray(); data[1].value = SHA512(data[1].value); // sha then encrypt on api.php page data = JSON.stringify(data); $("#loginButton").html('<i class="fa fa-spinner fa-pulse fa-lg fa-fw"></i> Login'); $.ajax({ type: "POST", url: "api.php", data: {"process": process, "data": data}, success: function(data) { if (data.response.state == "success") { // if api.php returns success, redirect to homepage } else { // if api.php returns failure, display error } }, error: function(jqXHR, textStatus, errorThrown, data) { // error handling }, dataType: "json" }); }
1. Проверьте заголовок ORIGIN
Как указано OWASP , этого недостаточно, но рекомендуется:
Хотя тривиально обманывать любой заголовок из вашего собственного браузера, как правило, это невозможно сделать при атаке CSRF, за исключением уязвимости XSS. Вот почему проверка заголовков является разумным первым шагом в вашей защите CSRF, но поскольку они не всегда присутствуют, она обычно не считается достаточной защитой сама по себе.
И Mozilla :
Заголовок Origin считается полезным для предотвращения кражи данных JSON и CSRF. Информация, предоставленная Origin – немного контекстной информации о создании запроса, должна предоставлять подсказки веб-серверам о достоверности запросов […]
Проверка заголовка HTTP_ORIGIN
может быть записана как:
header('Content-Type: application/json'); if (isset($_SERVER['HTTP_ORIGIN'])) { $address = 'http://' . $_SERVER['SERVER_NAME']; if (strpos($address, $_SERVER['HTTP_ORIGIN']) !== 0) { exit(json_encode([ 'error' => 'Invalid Origin header: ' . $_SERVER['HTTP_ORIGIN'] ])); } } else { exit(json_encode(['error' => 'No Origin header'])); }
1. (бис) Проверьте заголовок REFERER
Опять из OWASP :
Если заголовок Origin отсутствует , убедитесь, что имя хоста в заголовке Referer соответствует началу сайта. Проверка рефератора является широко используемым методом предотвращения CSRF на встроенных сетевых устройствах, поскольку для него не требуется состояние для каждого пользователя. Этот метод смягчения CSRF также широко используется с неаутентифицированными запросами […]
Проверка HTTP_REFERER
также довольно проста в PHP с помощью $_SERVER['HTTP_REFERER']
, вы можете просто обновить приведенный выше код.
Будьте осторожны с проверкой, которая всегда должна быть действительно конкретной: не проверяйте example.com или api.example.com, а полный https://example.com . Зачем ? Потому что вы можете обмануть эту проверку с помощью источника, такого как api.example.com.hacker.com .
2. Сгенерировать токены CSRF
Здесь объясняется хорошо объясненный ответ, специфичный для PHP :
Создайте токен:
session_start(); if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); }
Добавьте его в свои сгенерированные представления через мета (например, Github):
<meta name="csrf-token" content="<?= $_SESSION['csrf_token'] ?>">
Настройка jQuery ajax вызывает включение этого токена:
$.ajaxSetup({ headers : { 'CsrfToken': $('meta[name="csrf-token"]').attr('content') } });
Серверная проверка ваших запросов AJAX:
session_start(); if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } header('Content-Type: application/json'); $headers = apache_request_headers(); if (isset($headers['CsrfToken'])) { if ($headers['CsrfToken'] !== $_SESSION['csrf_token']) { exit(json_encode(['error' => 'Wrong CSRF token.'])); } } else { exit(json_encode(['error' => 'No CSRF token.'])); }
Большинство фреймворков PHP имеют свою собственную реализацию CSRF, которая более или менее основана на том же принципе.
3. Sanitize подтвердите ввод пользователя.
Вы всегда должны фильтр espace и проверить их .
4. Защитите свой сервер
5. Никогда не доверяйте пользовательскому вводу
Как сказал @ blue112, это один из самых элементарных принципов безопасности .
Короткий ответ: вы не можете защитить свою клиентскую сторону.
Длительный ответ:
Вы не можете сделать ничего, чтобы браузер показал, что это на самом деле ваш код javascript, который работает на стороне клиента. Тогда очевидное действие, которое нужно предпринять, является самым простым: НИКОГДА НЕ ДОПУСКАЙТЕ ПОЛЬЗОВАТЕЛЬ.
Это означает, что по мере того, как вы начали делать, защита вашей серверной части с помощью сеанса, ограничение скорости, проверка данных, fail2ban (запрещение IP-клиента после определенного количества сбоев), мониторинг журнала …
лучший способ по-прежнему заключается в обеспечении защиты на стороне сервера, и если бы я был зарегистрированным пользователем на сайте, я бы также смог проверить токен csrf на своем метатеге и подделать скрипт на сервер. Таким образом, уверенная ставка – проверка на стороне сервера