Безопасный OAuth в Javascript - PullRequest
20 голосов
/ 27 мая 2011

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

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

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

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

ЧтоЯ планирую реализовать следующее:

  • Пользователь заходит на веб-сайт в браузере.
  • Сайт выдает им файл cookie с ключом сеанса.
  • Затем наше расширение берет этот файл cookie и передает его в API.
  • API проверяет, является ли он действительным и активным сеансом, и выдает расширению свои токены доступа.
  • Эти токены действуют в течениемаксимум один час до истечения срока их действия.
  • Также будут установлены более низкие ограничения на размер файлов cookie, выпущенных JavaScript.

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

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

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

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

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

Ответы [ 3 ]

8 голосов
/ 09 июня 2011

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

  1. OAuth поддерживается только в браузерах, которые имеют LocalStorage
  2. Форма входа будет проверять LocalStorage на наличие ключей OAuth и автоматически проверять вход в OAuth, если существуют ключи OAuth.
  3. В форме входа в систему установлен флажок «запомнить меня», поэтому для пользователя при регистрации могут быть созданы токены OAuth.
  4. При успешном входе в систему, запомните меня:
    • найдите или создайте ClientApplication с именем, равным User Agent, и при необходимости создайте токены
    • ответьте тегом javascript в ответе HTML.Тег javascript вызовет функцию javascript с токенами, переданными в качестве аргументов.Эта функция сохранит токены OAuth в LocalStorage.
  5. Неудачная попытка входа в OAuth:
    • ответит тегом javascript в ответе HTML.Тег javascript вызовет функцию javascript для очистки настроек LocalStorage для токенов OAuth.Это предотвратит дополнительные попытки входа в OAuth.
3 голосов
/ 07 февраля 2012

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

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

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

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

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

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

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

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

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

2 голосов
/ 10 июня 2011

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

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

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

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