Как отправить безопасные запросы AJAX с PHP и jQuery

Проблема

Поэтому некоторое время я экспериментировал с различными подходами AJAX при отправке данных на сервер, которые будут обрабатываться и храниться в базе данных MySQL.

Страница, на которую запрос AJAX попадает на api.php , использует подготовленные заявления PHP PDO для сохранения данных, поэтому инъекции MySQL на самом деле не являются проблемой, а пароли или данные, которые необходимо зашифровать, также обрабатываются api.php который api.php ' Что я прошу здесь. Мой вопрос больше связан с тем, как обеспечить безопасность данных при передаче с клиента на сервер.

Подходы

В настоящее время у меня (для примера входа в систему, который я привел ниже):

  • SSL-сертификат / HTTPS, работающий в домене.
  • Определенный запрос AJAX (очевидно, не этот пример запроса на вход, поскольку для начала не существует сеанса) будет работать, только если PHP-сессия действительна на сайте (используется в обоих login.php как login.php и api.php ).
  • api.php при api.php при доступе к функциям.
  • PHP PDO подготовил инструкции при взаимодействии с базой данных внутри api.php .
  • Шифрует конфиденциальные данные внутри api.php (не относится к вопросу).

Вопросы

Наконец, мои вопросы:

  1. Является ли такой подход к использованию асинхронных HTTP-запросов (Ajax) достаточно безопасным для использования, а не просто отправкой данных на страницу PHP и перенаправлением вперед? (Так как это улучшает опыт пользователя).
  2. Как я могу проверить, что данные, которые отправляет мой пользователь, не были изменены?
  3. Могу ли я сделать достаточно, чтобы защитить данные моего пользователя, если нет, что еще я могу сделать?

Пример

Я понимаю, что у каждого есть разные подходы к обработке данных своего сайта и транспортировке этих данных. Я также понимаю, что независимо от того, что вы делаете, вы никогда не можете быть защищены на 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 :

  1. Создайте токен:

     session_start(); if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } 
  2. Добавьте его в свои сгенерированные представления через мета (например, Github):

     <meta name="csrf-token" content="<?= $_SESSION['csrf_token'] ?>"> 
  3. Настройка jQuery ajax вызывает включение этого токена:

     $.ajaxSetup({ headers : { 'CsrfToken': $('meta[name="csrf-token"]').attr('content') } }); 
  4. Серверная проверка ваших запросов 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. Защитите свой сервер

  • Ограничьте количество ваших запросов .
  • Используйте https как можно больше .
  • Блокируйте плохие запросы .
  • Защитите запросы POST .

5. Никогда не доверяйте пользовательскому вводу

Как сказал @ blue112, это один из самых элементарных принципов безопасности .

введите описание изображения здесь

Короткий ответ: вы не можете защитить свою клиентскую сторону.

Длительный ответ:

  • Использование AJAX столь же безопасно, как и отправка данных, например, с помощью формы.
  • Использование HTTPS предотвращает доступ пользователей к данным пользователя, поэтому фактические данные, отправленные пользователем, безопасны.

Вы не можете сделать ничего, чтобы браузер показал, что это на самом деле ваш код javascript, который работает на стороне клиента. Тогда очевидное действие, которое нужно предпринять, является самым простым: НИКОГДА НЕ ДОПУСКАЙТЕ ПОЛЬЗОВАТЕЛЬ.

Это означает, что по мере того, как вы начали делать, защита вашей серверной части с помощью сеанса, ограничение скорости, проверка данных, fail2ban (запрещение IP-клиента после определенного количества сбоев), мониторинг журнала …

лучший способ по-прежнему заключается в обеспечении защиты на стороне сервера, и если бы я был зарегистрированным пользователем на сайте, я бы также смог проверить токен csrf на своем метатеге и подделать скрипт на сервер. Таким образом, уверенная ставка – проверка на стороне сервера