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

Безопасный OAuth в Javascript

У меня есть api, который использует OAuth 1.0a для аутентификации приложений, использующих его. Он заменил старый api, который использовал несколько пользовательских построенных и hodge-podge вызовов, которые устарели.

Хорошо известно, что OAuth 1.0a не защищен (на стороне клиента) Javascript, поскольку он полагается на секрет секретности пользователя. Это невозможно, так как источник всегда доступен для просмотра.

У нас есть расширения браузера для Chrome, Firefox, IE и Safari, которые должны использовать этот api в будущем. Эти расширения написаны в основном или полностью в Javascript, и, следовательно, проблема безопасности.

Эти расширения являются собственными и поэтому могут иметь собственные методы аутентификации для получения своих токенов доступа.

То, что я планирую реализовать, следующее:

  • Пользователь регистрируется на веб-сайте в браузере.
  • Веб-сайт выдает им файл cookie с ключом сеанса.
  • Наше расширение затем берет этот файл cookie и передает его на api.
  • Api проверяет, что это действительный и активный сеанс, и выдает расширение своим токенам доступа.
  • Эти токены длится максимум один час до истечения срока их действия.
  • Там также будут ограничены ограничения на файлы cookie, обработанные javascript.

Он работает при следующих предположениях:

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

Мой вопрос в том, является ли это безопасным методом ограничения доступа к api? Есть ли лучшие?

Несколько примечаний. Я знаю, что хром-расширения могут запрашивать разрешение на доступ к вашим файлам cookie для определенного сайта. Я считаю, что расширения Firefox также могут сделать это.

Очевидно, что мы не хотим, чтобы наши файлы cookie были доступны через javascript на любой странице, иначе мы бы подверглись атакам XSS, поэтому они должны быть доступны только через расширения.

4b9b3361

Ответ 1

Я написал сайт, который делает логин OAuth через javascript-библиотеку для OAuth. Это рабочий процесс:

  • OAuth поддерживается только в браузерах, у которых есть LocalStorage
  • Форма входа в систему проверит LocalStorage для ключей OAuth и автоматически попросит логин OAuth, если существуют ключи OAuth.
  • Есть флажок "запомнить меня" в форме входа, поэтому у пользователя могут быть маркеры OAuth, созданные для них при входе в систему.
  • Успешный логин/запомнить меня будет:
    • найти или создать ClientApplication с именем, равным User Agent, и при необходимости создать маркеры
    • ответьте на тег javascript в ответе HTML. Тег javascript вызовет функцию javascript с токенами, переданными в качестве аргументов. Эта функция сохранит токены OAuth в LocalStorage.
  • Неудачная попытка входа в систему OAuth будет:
    • ответьте на тег javascript в ответе HTML. Тег javascript вызовет функцию javascript, чтобы очистить настройки LocalStorage для токенов OAuth. Это предотвратит дополнительные попытки входа в систему OAuth.

В этом процессе есть несколько подробностей, я могу рассказать вам об этом, если вы хотите, чтобы я это сделал.

Ответ 2

Несколько соображений для тех, кто приходит на этот пост после:

  • "Это безопасно" → это зависит от того, от каких угроз мы хотим защитить. В следующих пунктах я предполагаю, что решение уже подразумевает надежную сетевую ссылку (для предотвращения попыток перехвата транзитных токенов или учетных данных). Однако в описании отсутствует ключевой элемент, так как он не упоминает, защищаем ли мы API от неавторизованных пользователей (людей) или от несанкционированных клиентов API (например, из-за неактивного расширения в браузере). Первое может быть достигнуто довольно легко с доступными открытыми стандартами, в то время как следует забыть о попытке предотвратить доступ от несанкционированных расширений, поскольку модель принципиально полагается на технологию с открытым исходным кодом на стороне клиента. Это касается безопасности рабочей станции, а не разработки надежного механизма аутентификации/авторизации. Мы все еще можем реализовать какой-то механизм аутентификации расширения, но он будет бесполезен для тех, кто знает, как читать исходный код расширений.

  • В принципе есть два способа разработки платформы. Либо используя API, чтобы разрешить запрос службы проверки подлинности. Или используя доступ на основе токенов, в котором API будет запрашивать наличие действительного токена в каждом запросе, который он получает, не являясь его эмиттером. Это означало бы расширение службы аутентификации с помощью новой роли: эмитента билетов API, что редко бывает интересно. При чтении предложения кажется, что мы объединяем оба мира, перенаправляя токен сеанса в API. Это неправильно. Во-первых, это не значит, что для этого был предназначен маркер сеанса cookie. Во-вторых, это заставляет API внедрять какую-то синхронную связь в реальном времени с системой управления сеансом службы аутентификации пользователя → , которую мы можем легко избежать.

  • Я предполагаю, что главная цель - защитить API от неавторизованных пользователей и что мы не будем пытаться решать проблемы, связанные с доступом к локальной системе.

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

  • Это изменяет исходный сценарий следующим образом:

    • Пользователь регистрируется на веб-сайте с помощью браузера.
    • На веб-сайте выдается файл cookie, содержащий ключ сеанса.
    • Расширение теперь может отправлять запрос на билет в службу аутентификации. Запросы будут включать токен сеанса (поведение браузера по умолчанию) и поэтому будут проходить проверку подлинности.
    • После того, как добавочный номер получит билет, расширение перенаправляет его в API и запрашивает токен сеанса.
    • API проверяет билет путем опроса диспетчера сеансов. Если менеджер сеансов говорит "да, я сделал этот билет, и он все еще действителен", API генерирует токен сеанса и возвращает его в расширение. Этот токен будет вставлен во все последующие запросы, а не в билет. Это позволит избежать лишней рабочей нагрузки диспетчера сеансов.
    • Токен (не путайте его с билетом) может иметь очень короткий срок службы, например, несколько минут → если он истекает, расширение просто возвращается в службу проверки подлинности и запрашивает новый билет (вернитесь к шагу 3 выше).
  • Вышеупомянутое решение в основном зависит от того, насколько безопасны и билет, и токен. Их дизайн должен, по крайней мере, выполнять контрмеры против следующих 5 оставшихся угроз: i) попытки угадать билет/токен (безопасное достаточно случайное поколение), ii) попытки вычислить билет/токен (достаточно большая энтропия), iii) попытки повторное использование билета/токена (истечение срока действия), iv) попытки вмешательства в действительный билет/токен (проверка целостности), v) попытки доступа к API без действительного токена/билета (проверка маркера в каждом запросе, который получает API).

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

Надеюсь, что это поможет.

Ответ 3

Итак, у вас есть сайт на example.com, и ему нужен доступ к api.com. Ваше расширение предполагает, что пользователь вошел в систему example.com, извлекает файл cookie сеанса и передает его на api.com, чтобы получить токен Oauth. Звучит разумно, но есть более простые способы без необходимости писать плагины браузера.

В вашем случае api.com собирается общаться с example.com для проверки cookie сеанса. Между этими двумя системами существует сильная зависимость. OAuth обычно используется там, где example.com и api.com НЕ доверяют друг другу.

Поскольку две системы уже имеют какое-то доверие друг к другу, вы можете сделать различные вещи для упрощения архитектуры:

  • Вы можете создать прокси-сервер, размещенный на example.com/api/*, который проверяет сеанс, а затем слепо пересылает api.com/*. Что касается браузера, запросов на междоменные запросы нет, поэтому все отлично работает.
  • Вы можете использовать федеративный вход в домен. Это сложнее, чем прокси-метод, но вы можете легко найти существующую реализацию для своей платформы.