http - аутентификация - делаем rest api



Как сделать аутентификацию с помощью REST API?(Браузер+собственные клиенты) (0)

Я создаю веб-приложение с помощью Rails. На данный момент я использую Devise с сеансами HTTP, которые довольно легко настроить, и он работает хорошо.

Приложение состоит из одного URL-адреса, предоставляющего веб-приложение AJAX. Остальные доступные URL принадлежат REST API. Таким образом, все и каждый маленький запрос данных выполняется через AJAX.

Теперь я хотел бы расширить все, чтобы поддерживать родных клиентов. Я много читал об авторизованных языках, не поддерживающих HTTP, cookie, xsrf и т. Д. И теперь я чувствую, что у меня нет безопасного приложения, потому что всегда есть способ захватить некоторые его части ,

1 .: HTTP-сессия Vs. токен аутентификации

Какая разница? Я не понимаю.

  • HTTP-сессия:

    1. Клиент запрашивает URL-адрес (первый запрос на сервер)
    2. Сервер дает обычный ответ плюс некоторая уникальная строка (== session ID)
    3. Клиент должен отправить эту строку с каждым запросом (который делается автоматически с использованием HTTP-заголовка)
    4. Клиент регистрируется в -> Сервер запоминает, что данный идентификатор сеанса теперь зарегистрирован
    5. Клиент посещает страницу, для которой требуется auth -> ничего особенного, потому что идентификатор сеанса будет автоматически отправляться на сервер через HTTP-заголовок
  • токен authen:

    1. URL-адрес запроса клиента (первый запрос на сервер)
    2. Сервер просто дает нормальный ответ без какого-либо ключа или токена или идентификатора
    3. (здесь ничего особенного)
    4. Клиент регистрируется -> Сервер создает токен аутентификации и отправляет этот токен клиенту внутри ответа
    5. Страница визитов клиента, для которой требуется авторизация -> Клиент должен отправить токен авторизации

Для меня оба способа выглядят довольно похожими. С Rails я также могу выбрать сохранение сеанса внутри базы данных ... Devise будет делать то же самое с токеном authen auth.

2: Метод аутентификации

Прямо сейчас я использую POST /users/sign_in с {"user":{"email":"[email protected]","password":"p455w0rd"}} .

Но есть и другие возможности, такие как HTTP basic auth и HTTP digest auth, но также такие решения, как oAuth (слишком большой для моей цели).

Из того, что я читал:

  • Что касается безопасности sign_in, то нет никакой разницы между текущим POST /users/sign_in и базовым протоколом HTTP. Оба используют clearartext.
  • Для sign_out HTTP базовый auth имеет недостаток: Выход возможен только при закрытии окна браузера
  • HTTP-дайджест auth имеет огромное преимущество: он вообще не передает пароль (просто хэш пароля плюс произвольная сгенерированная строка)
  • (Немецкий) Wikipedia говорит: HTTP-дайджест auth не поддерживается всеми браузерами. Может быть, эта информация - путь к старому ?!

Что мне нужно:

  • имена пользователей и хэшированные пароли (bcrypt), хранящиеся в базе данных.
  • пользователь может изменить свой пароль, и пароль не должен быть отправлен открытым текстом. (Такая же проблема возникает, когда речь идет о пользователе sign_up). Возможные решения?
    1. конечно: использование SSL / TLS
    2. клиент запрашивает want_to_change_password_salt и использует его для шифрования пароля на стороне клиента. но (?!) таким образом я отправил важную часть хэшированного пароля по проводу плюс хешированный пароль. Звучит неуверенно для меня ?!

3: Тонер CSRF

Как уже было сказано выше, сейчас у меня есть обычный веб-сайт AJAX с использованием API REST. Он имеет защиту XSRF: веб-сайт доставлен рельсами и, таким образом, встроил токен XSRF. Я прочитал его с помощью AJAX и передал его при выполнении POST . Затем Rails возвращает запрошенные данные и новый токен XSRF, который затем я использую для следующего POST .

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

  • Создайте ресурс REST-токена XSRF. Таким образом, (native) клиент должен запросить токен XSRF с этого ресурса, прежде чем он сможет выполнить первый POST .
  • Полностью отключите защиту XSRF.

Вопросов:

  • Как работает защита XSRF (в Rails)? Как сервер знает, какой токен принадлежит клиенту? Единственный способ, о котором я могу думать, - это сеансы. Это предположение приводит к:
  • Если я отключу сеанс, чтобы создать полностью автономный REST API, защита XSRF больше не будет работать. Правильно?

4: токен без аутентификации

Здесь у меня в основном много вопросов:

  • Имеют ли они те же проблемы безопасности, что и сеансы HTTP? Я имею в виду: кража идентификатора сеанса имеет такой же эффект, как кража токена аутентификации. Правильно?
  • Истечение токена авторизации должно работать так же, как и с сеансами HTTP: сервер должен хранить где-нибудь (база данных соответственно сеанс) отметку времени и проверять это.
  • sign_out тоже работает?
    • Сессия: Уничтожьте сеанс на сервере
    • Маркер аутентификации: уничтожьте токен на сервере
  • Из того, что я прочитал, должно быть безопаснее хранить токен аутентификации внутри HTTP-заголовка (точно так же, как идентификатор сеанса), поскольку журналы сервера могут содержать параметры GET и, следовательно, могут содержать токен.
  • Должен ли он быть просто аутентифицированным токеном или было бы лучше, если бы клиент также передал свой user_id или даже хешированный пароль? HERE я прочитал, что клиент должен отправить:
    1. user_id
    2. expiration_date
    3. хэш (или что такое HMAC?) из [ user_id , expiration_date , SECRET_KEY ]. Где SECRET_KEY - это в основном случайная строка, сгенерированная сервером.

Извините за пост huuuge, но безопасность важна! И я не хочу делать ошибки дизайна, которые, вероятно, могли бы предоставить частные данные.

Спасибо :)

Вот немного новой информации и новых вопросов ;-) :

5: Родные клиенты

Что касается родных клиентов, то нет ( простого ) способа использования сеансов:

  • У родного клиента нет браузера

  • Таким образом, он не будет легко обрабатывать файлы cookie (и без файлов cookie нет обычной обработки сеанса)

Таким образом, существует 3 возможных варианта:

  1. Реализация обработки сеанса для собственных клиентов. Это будет выглядеть так:

    1. Авторизоваться
    2. читать HTTP Заголовок ответа для получения файлов cookie
    3. сохраните все данные cookie, которые вам нужны (особенно тот, у кого есть сеанс) локально
    4. отправьте этот идентификатор сеанса с каждым запросом, который вы выполняете
  2. Не используйте сеансы вообще. С точки зрения местного клиента это почти то же самое, что и 1 .:

    1. Авторизоваться
    2. Получите определенный токен аутентификации из заголовка HTTP или тела ответа (это ваше приложение, хотя оно зависит от вас)
    3. сохранить этот токен локально
    4. отправьте этот токен с каждым запросом
  3. Гибридный подход. Это в основном означает, что сервер должен различать браузер и собственный клиент, а затем проверять предоставленные идентификаторы сеанса и данные сеанса или (для собственных клиентов) проверять предоставленный токен аутентификации.

6: Ток CSRF с апатридом (= нет сеанса / без файлов cookie) auth

CSRF Protection защищает ваших пользователей от вредоносных веб-сайтов, которые пытаются выполнить какой-либо запрос в вашем API от имени вашего зарегистрированного пользователя, но без вашего ведома пользователя. Это довольно просто при использовании сеансов:

  1. Пользователь регистрируется в вашем API
  2. Создание сеанса
  3. В вашем браузере пользователей будет установлен файл cookie с этим идентификатором сеанса
  4. Каждый запрос, который выполняет ваш пользователь на ваш API, автоматически аутентифицируется, поскольку браузер отправляет все файлы cookie (включая идентификатор сеанса) вместе с каждым запросом на ваш API

И поэтому атакующий веб-сайт просто должен сделать следующее:

  1. Напишите пользовательский HTML <form> который указывает на ваш API
  2. Позвольте пользователю как-то нажать кнопку « Submit

Конечно, эта форма будет выглядеть примерно так:

<form action="http://your.api.com/transferMoney" method="post">
  <input type="hidden" name="receiver" value="ownerOfTheEvilSite" />
  <input type="hidden" name="amount" value="1000.00" />
  <input type="submit" value="WIN MONEY!!" />
</form>

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

  1. Защита CSRF необходима только потому, что браузеры автоматически отправляют файлы cookie.

  2. Родные клиенты не нуждаются в защите CSRF (конечно: ваш браузер не может получить доступ к данным аутентификации (токен, файл cookie и т. Д.) Вашего родного приложения, а ваше родное приложение не будет использовать браузер для связи с API)

  3. Если у вас есть дизайн API, который не использует Cookies для аутентификации пользователя, нет возможности сделать CSRF. Поскольку злоумышленник должен знать токен аутентификации и явно отправлять его вместе со злонамеренным запросом.

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

7: Правильные HTTP-методы для выбора

Вход / Вход и выход / Выход:

Никогда не используйте GET для (по крайней мере) трех причин:

  1. Защита CSRF в большинстве случаев защищает только POST, PUT, PATCH и DELETE, и поэтому CSRF может войти в систему без его знаний при использовании запроса GET

  2. Запросы GET никогда не должны изменять состояние приложения. Но при использовании сеансов состояние приложения изменяется при входе / выходе из системы, потому что сеанс создается или уничтожается.

  3. При использовании запроса GET и передачи информации аутентификации в качестве параметров URL (например, http://your.api.com/login?username=foo&password=bar ) возникает другая проблема: журналы сервера! Большинство серверов просто регистрируют каждый HTTP-запрос, включая все параметры URL. Это означает: если ваш сервер будет взломан, вам не нужно взломать хэши паролей из вашей базы данных, они должны просто посмотреть файлы журналов сервера. Кроме того, злоумышленник может также прочитать информацию для входа для каждого пользователя. Решения:

    • Используйте POST (или любой другой метод) и отправляйте информацию об аутентификации внутри тела запроса. Или:
    • Отправьте информацию об аутентификации в заголовки HTTP. Поскольку эта информация обычно не отображается в файлах журнала сервера. Или:
    • Посмотрите конфигурацию сервера и сообщите ему, чтобы удалить каждый параметр URL, который называется «пароль» (или обфускация, поэтому URL-адрес становится login?username=foo&password=*** внутри журналов). Но я предлагаю просто использовать тело запроса для такого рода информации вместе с методом POST.

Таким образом, вы можете использовать, например:

POST http://your.api.com/authentication для входа

DELETE http://your.api.com/authentication для выхода из системы

8 .: Пароли и Хеширование

Аутентификация работает только с секретным ключом. И, конечно, этот ключ должен храниться в секрете. Это означает:

  • Никогда не храните пароль в открытом виде в своей базе данных. Доступно несколько библиотек для обеспечения безопасности. На мой взгляд, лучшим вариантом является bcrypt .

  • bcrypt : он оптимизирован для хэш-паролей. Он автоматически генерирует соль и хеширует пароль несколько раз (раунды). Кроме того, сгенерированная хэш-строка содержит все необходимое: количество раундов, соль и хеш. Хотя вам просто нужно сохранить эту одну String, и нет необходимости писать что-либо вручную.

  • конечно, вы также можете использовать любую другую сильную библиотеку хэширования. Но для большинства из них вы должны реализовать соление и использовать более 1 раунда самостоятельно. Кроме того, они не дают вам всего лишь одну строку, например, bcrypt, хотя вам нужно управлять собой, чтобы хранить раунды, соль и хэш и собирать их впоследствии.

  • rounds : Это просто, как часто пароль должен быть хэширован. При использовании 5000 раундов хеширующая функция вернет хэш хэш хэша хэша пароля . В принципе, это единственная причина: это стоит мощности процессора! Это означает: когда кто-то пытается нанести вред вашему хешу, он занимает 5000 раз дольше при использовании 5000 раундов. Для вашего приложения это не имеет большого значения: если пользователь знает свой пароль, он не узнает, если сервер принял 0.0004ms или 2ms для его проверки.

  • Хорошие пароли : лучшая функция хэширования бесполезна, если пароль слишком прост. Если он может быть взломан, используя словарь, это не имеет большого значения, если вы хэшировали его 5000 раундами: это может занять несколько часов дольше, но что за несколько часов, если это может быть месяцы или годы? Хотя убедитесь, что пароли вашего пользователя содержат обычные рекомендации (нижний + верхний регистр + цифры + специальные символы и т. Д.).

9 .: Отправка зашифрованных паролей по кабелю

Если вы не можете (или не хотите) полагаться на HTTPS, но не хотите отправлять пароли в открытом тексте при входе в систему, вы можете использовать асимметричную криптографию ( http://en.wikipedia.org/wiki/Public-key_cryptography ).

Этот сервер создает пару ключей (открытый ключ и закрытый ключ). Открытый ключ предоставляется клиентам, закрытый ключ должен быть конфиденциальным!

Клиент может теперь шифровать данные с помощью открытого ключа, и эти данные могут быть дешифрованы только владельцем закрытого ключа (= сервер).

Это не должно (!) Использоваться для хранения паролей в базе данных, потому что если ваш сервер будет взломан, хакер будет иметь зашифрованные пароли и закрытый ключ для дешифрования. Хотя продолжайте использовать некоторый алгоритм хэширования (например, bcrypt) для хранения паролей в вашей базе данных. Другая причина заключается в том, что вы можете легко создать новую пару ключей, если вы считаете, что кто-то взломал вас на шифрование.

HTTPS в основном работает одинаково. Хотя, если ваше приложение использует HTTPS (что рекомендуется), с точки зрения безопасности не может быть большой пользы. Но, как указано выше, если вы не можете использовать HTTPS по какой-либо причине или не доверяете ему, это способ создать собственное безопасное соединение.

И имейте в виду, что реальное соединение HTTPS шифрует все (!) Соединение и все данные, а не только данные пароля. И он шифрует его в обоих направлениях: от клиента к серверу и от сервера к клиенту.





stateless