it-swarm.com.ru

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

Эта проблема

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

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

Подходы

В настоящее время у меня есть (для примера входа в систему я включил ниже):

  • Сертификат SSL/HTTPS работает на домене.
  • Определенный запрос AJAX (очевидно, не этот пример запроса на вход в систему, так как сессия не начинается) будет работать только в том случае, если сеанс PHP действителен для всего сайта (используется в обоих случаях login.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"
    });
}
24
LukeXF

1. Проверьте заголовок источника

Как определено 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. Зачем ? Потому что вы можете подделать эту проверку с помощью Origin, например 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 подтвердить ввод пользователя.

Вы всегда должны фильтр входные данные пробела и проверить их .


4. Защитите свой сервер


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

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

enter image description here

50
Ivan Gabriele

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

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

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

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

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

1
blue112

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

0
Osemwota Osagie Anthony