Подтвердить что ты не робот

Использование HTTP-аутентификации

Я создаю REST API в PHP для работы с приложением на основе JavaScript. Все запросы обрабатываются как JSON, а некоторые запросы требуют аутентификации.

Пример запроса:

$.ajax({
    type: 'GET',
    url: 'http://domain.com/api/posts/recent.json',
    headers: {
        Authorization: 'X-TRUEREST ' + $.param({
            username: 'johndoe',
            password: '********'
        })
    },
    success: function(response){
            // Handle response here (includes auth errors too)
    },
    error: function(a,b,c) {

    }   
});

Я основал использование заголовков HTTP Authentication для кода в этом плагине: https://github.com/kvz/cakephp-rest-plugin/blob/master/Controller/Component/RestComponent.php#L532

Как вы можете видеть, они принимают переданные параметры с заголовком, а затем они используются для входа пользователя в систему, если они еще не были. Из того, что я могу сказать, они ожидают, что аутентификационные данные будут переданы с запросом на данные.

Примером этого является (обратите внимание не на использование CakePHP в моем примере приложения):

if ( $loggedIn ) { // logged in is true of false based on session existing

    // Then return the JSON as normal

} else {

    // Grab HEADERS INFO

    $headers = $_SERVER['HTTP_AUTHORIZATION'];
    $parts = explode(' ', $_SERVER['HTTP_AUTHORIZATION']);

    // Then use the parts to find a user in the DB... and populate $user

    if($user){

        $this->Auth->login($user); // login the user with our authentication code

        // Then return JSON as normal

    } else {
        print json_encode(array('auth'=>false))
    }

}

Несколько вопросов, которые у меня есть:

Вопрос 1: Зачем использовать HTTP-аутентификацию и заголовки? Насколько я могу судить, они ничего мне не предлагают, если я неправильно их использую? Почему бы просто не пропустить имя пользователя и пароль в параметре данных JS?

Вопрос 2: Как уже говорилось ранее, я основывал свой дизайн API на плагине Cake выше, но из того, что я вижу, они ВСЕГДА передают имя пользователя и пароль с каждым запросом, а затем решают использовать его или нет, если пользователь вошел в систему. Правильно ли это? Для меня кажется более вероятным, что аутентификация и запросы на данные должны обрабатываться отдельно. В противном случае мне пришлось бы хранить имя пользователя и пароль в моем JavaScript где-нибудь, чтобы я мог отправлять его с каждым запросом.

Это подводит меня к следующему вопросу...

Вопрос 3:. Как узнать, вошел ли пользователь в систему? Я могу установить переменную в true, а затем передать это как часть моего JSON с каждым запросом, но может ли сеанс работать с внешним устройством?

4b9b3361

Ответ 1

Если вы проектируете REST api, вы должны придерживаться принципов REST. Для аутентификации выделяются два важных момента:

  • Идентификация ресурсов через URI
  • Состояние переходит через серверные ссылки.

Чтобы придерживаться принципа 1, вам нужно сохранить аутентификацию вне вашего URI. http://example.org/list-of-stuff?auth-token=12345 не является другим ресурсом от http://example.org/list-of-stuff?auth-token=67890, поэтому он не должен иметь другого URI. Наличие разных URI также не позволяет кэшировать ресурс для разных пользователей.

В общем случае, если ресурс будет отличаться в зависимости от некоторого условия, это условие должно быть в URI. Например, на многих веб-сайтах есть URL /profile, но какой профиль вы видите, зависит от состояния невидимого "кто входит в систему". Это не RESTful. Вместо этого URL должен содержать пользователя, например. /profiles/username. Независимо от того, действительно ли вы видите, что этот ресурс зависит от того, разрешено ли вам видеть его, что зависит от того, авторизована ли вас в качестве пользователя, который разрешен. Аутентификация - это отдельный слой от идентификации ресурсов. (Например, предположим, что у вас есть пользователь admin, который может видеть профили других пользователей.Если у вас есть только /profile url, как бы вы создали метод для просмотра других профилей? Очевидно, что наличие ресурса отличается от способность видеть это и от того, кто смотрит на него.)

Итак, мы установили, что аутентификация не должна быть через параметры в URI. Поскольку мы используем HTTP, мы можем либо предоставить его в заголовке, либо предоставить его вне HTTP.

Хотя это не очень распространено, некоторые REST apis обрабатывают аутентификацию на уровне SSL с использованием клиентских сертификатов. Это замечательно с технической точки зрения, но пользовательский интерфейс является непонятным и ужасным. Хотя эта статья с 2008 года, ничего не улучшилось. Этот подход также нелегко обрабатывается сценарием из браузера JS, и даже вне браузера громоздко писать приложение, которое должно предоставлять клиентские сертификаты. Разработка на стороне сервера тоже затруднена, потому что большинство сред веб-скриптов не дают вам простого доступа к материалам на уровне SSL вообще, не говоря уже о более эзотерических функциях SSL, таких как клиент-сертификаты. Ваша заявка может быть не в состоянии узнать, какой сертификат был предоставлен с запросом.

Итак, это оставляет HTTP в заголовке. Мы можем либо использовать традиционную аутентификацию на основе файлов cookie, где мы "входим в систему" ​​на специальном URL-адресе и получаем токен обратно или HTTP-аутентификацию, которая поддерживается HTTP.

HTTP-аутентификация намного выше с точки зрения принципов RESTful, поскольку она не имеет гражданства. (Это делает ваш третий вопрос бессмысленным - нет "вошедшего в систему" ​​или "выведенного из системы" состояния - вы либо предоставили правильные учетные данные для запроса, либо вы его не сделали!) Вам не нужно, чтобы вы впервые посетили специальный url и получил волшебный токен, который вам нужно сохранить (который может внезапно истечь), вы просто отправляете запрос с вашими учетными данными каждый раз. Если у вас нет доступа к ресурсу, есть специальный код ответа HTTP (401) и заголовок (WWW-Authenticate, Authorization) и набор четко определенных действий. Он также расширяется с различными методами авторизации. Там также много поддержки javascript, по крайней мере, если вы придерживаетесь XmlHTTPRequest. (Heck, jQuery 1.7.2 даже имеет параметры имени пользователя и пароля, поэтому вам даже не нужно самому base64-кодировать его самостоятельно!)

Недостатком является то, что только HTTP-методы аутентификации, которые широко используются и хорошо поддерживаются, являются Basic и Digest, и оба они не очень безопасны. Они, вероятно, прекрасны, если вы используете только https, но в противном случае они ужасны.

Также HTTP auth бесполезен для обычного использования браузером людьми: нет пользовательских страниц входа, нет возможности представить функциональность "забытого пароля" или другие настройки аутентификации, и все же разработчики браузеров не предоставили простой способ "выйти из системы" (т.е., забудьте учетные данные для текущего мира)!

Авторизация на основе файлов cookie предоставляет вам наибольший контроль, но вам необходимо поддерживать аутентификацию на сервере и на стороне клиента и беспокоиться о целом ряде других проблем безопасности, таких как фиксация сеансаили даже то, что составляет сессию! Это IP-адрес, пользовательский агент, некоторая комбинация? Как долго должен пройти аутентифицированный сеанс до истечения срока его действия? Что делать, если есть прокси-сервер и часто меняется IP-адрес? Что нам делать, когда истекает магический токен? Что делать, если пользователь не авторизован? (Вы не можете использовать ответ HTTP 401 - вам нужно определить свой собственный метод, специфичный для вашего сайта.) По сути, вам нужно определить свой собственный сложный сеанс и протокол аутентификации или принять чужой. По крайней мере, с помощью HTTP auth, единственное, что вам нужно беспокоиться, - это атаковать злоумышленник, читающий ваши заголовки Authenticate, и использование SSL решает эту проблему.

Ответ 2

Вопрос 1: Зачем использовать HTTP-аутентификацию и заголовки? Насколько я могу судить, они ничего мне не предлагают, если я неправильно их использую? Почему бы просто не пропустить имя пользователя и пароль в параметре данных JS?

HTTP-аутентификация здесь является личным выбором разработчика. Вы можете использовать OpenID. Вы можете использовать токен. Вы можете использовать HTTP Header Authentication. Вы можете использовать sessions/cookie. Heck, вы даже можете использовать RSA Key Authentication или SSL Client Certificates если вам понравилось.


Вопрос 2: Как было сказано ранее, я основывал свой дизайн API на плагине Cake выше, но из того, что я вижу, они ВСЕГДА передают имя пользователя и пароль с каждым запросом, а затем решают использовать его или нет, если пользователь зарегистрирован in. Правильно ли это? Для меня кажется более вероятным, что аутентификация и запросы на данные должны обрабатываться отдельно. В противном случае мне пришлось бы хранить имя пользователя и пароль в моем JavaScript где-нибудь, чтобы я мог отправлять его с каждым запросом.

Вы не должны раскрывать имя пользователя и пароль ничего в открытом тексте, когда-либо (технически вы даже не должны хранить его как таковой, но это не тот вопрос около). Используйте общедоступный токен с API или уникальный идентификатор файла cookie. Лично я использую $_SESSION["id"], чтобы узнать, вошел ли пользователь во что-либо. Пусть AJAX отправляет, а затем отображает ID на токен внутри, если вам нужно.


Вопрос 3: Как узнать, вошел ли пользователь в систему? Я могу установить переменную в true, а затем передать это как часть моего JSON с каждым запросом, но может ли сеанс работать с внешним устройством?

У меня есть функция, которую я использую для этого связанного в этом ответе. В идеале вы должны проверить правильность входа в систему с помощью сеанса и установить значение индекса (например, $_SESSION["id"]) для значения, уникального для этой учетной записи (обычно это их идентификатор базы данных).

Изменить: после прочтения комментариев на OP, вам нужно убедиться, что файл cookie сеанса находится на любом устройстве, которое было зарегистрировано, прежде чем делать запрос

Сделайте не поле value: true для входа в систему, так как это уязвимость безопасности.

Ответ 3

Я думаю, что вы смешиваете (возможно, специально) между передачей информации в REST api с использованием URI и авторизацией доступа к определенному серверу с помощью http simple Authentication.

HTTP-аутентификация также может использоваться для обработки пользователей, но это не будет очень хорошим выбором (как объясняется в других ответах). пользователи, сеансы, токены безопасности и т.д. должны обрабатываться логикой приложения, в то время как доступ api также может быть безопасно защищен сервером (с помощью простой или дайвинг-безопасности http, NTLM, фильтрации IP или любого другого). позволяя веб-серверу взять на себя некоторые проблемы с безопасностью/разделяющие проблемы/какой-то сайт для тестирования/и т.д.

пример scenerio обрабатывает http-защиту для доступа к защищенному серверу на сервере зоны тестирования, в то время как приложение REST api будет принимать и обрабатывать разных пользователей, токены, уровни разрешений и т.д. всем, кто прошел проверки безопасности сервера.

найдите question для получения дополнительной справки

Ответ 4

Вопрос 1: Зачем использовать HTTP-аутентификацию и заголовки? Насколько это возможно Я могу сказать, что они ничего мне не предлагают, если я их не использую неправильно? Почему бы просто не пропустить имя пользователя и пароль в данных парам JS?

Строка запроса является частью URI. URI является идентификатором ресурса REST, поэтому он является частью состояния ресурса. Идентификатор, учетные данные и т.д. Пользователя являются частью состояния клиента. Смешение состояния клиента и состояния ресурса путем добавления состояния клиента в URI было бы нарушением ограничения без учета состояния REST. Часть данных других запросов, таких как POST, PUT, DELETE, предназначена для описания представлений ресурсов, поэтому вам не следует отправлять с нее данные auth. Отправка заголовков - лучший подход, и поскольку HTTP имеет выделенный заголовок авторизации, вы должны использовать его.

Вопрос 2: Как было сказано ранее, я основывал свой дизайн API на Cake плагин выше, но из того, что я вижу, они ВСЕГДА передают имя пользователя и пароль с каждым запросом, а затем решили использовать его или нет, если пользователь вошел в систему. Правильно ли это? Для меня это кажется более вероятным что необходимо обрабатывать аутентификацию и запросы на данные в отдельности. В противном случае мне пришлось бы хранить имя пользователя и пароль в моем JavaScript где-нибудь, чтобы я мог отправить его с каждым запросом.

Ваш сервер должен аутентифицировать каждый запрос, чтобы оставаться без гражданства. Я не уверен в логике этого lib, я думаю, что логин - это неправильный термин для описания того, что происходит, но с точки зрения REST детали реализации не имеют значения, если он правильно использует стандарт HTTP, и связь не имеет статуса. Код изменился с тех пор, как вы задали свой вопрос.

Вопрос 3: Как узнать, вошел ли пользователь в систему? Я мог бы установить переменная в true, а затем передать это как часть моего JSON с каждым запрос, но может ли сеанс работать с внешним устройством?

Сервер не заботится о том, зарегистрирован ли клиент, поскольку это состояние клиента. Если вы отправляете запрос, требующий разрешения, то вам необходимо отправить данные, необходимые для аутентификации пользователя.