Реализация двухстороннего OAuth-провайдера - PullRequest
13 голосов
/ 29 марта 2010

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

У меня есть набор существующих API - некоторые на Java, некоторые на PHP - которые мне сейчас нужно обезопасить, и по ряду причин OAuth кажется правильным решением. К сожалению, моя неспособность отыскать нужные ресурсы, чтобы помочь мне запустить провайдера, ставит под сомнение эту теорию. Так как большая часть этого будет использовать API-интерфейс от системы к системе, мне потребуется реализовать двухстороннего поставщика. Имея это в виду ...

  1. Кто-нибудь знает какие-нибудь хорошие учебники по реализации двухстороннего OAuth-провайдера с PHP?
  2. Учитывая, что у меня есть защищаемые API на 2 языках, нужно ли реализовывать провайдера на обоих языках или есть способ создать провайдера как «фронт-контроллер», через который я могу направлять все запросы?
  3. Например, при защите служб PHP нужно ли защищать каждый API отдельно, включая необходимые ресурсы провайдера для каждого из них?

Спасибо за вашу помощь.

Ответы [ 2 ]

42 голосов
/ 08 июля 2011

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

У меня более или менее был тот же вопрос несколько месяцев назад, и я слышал об "OAuth" большую часть года. Я разрабатывал REST API, который мне нужно было обезопасить, поэтому я начал читать об OAuth ... и затем мои глаза начали закатываться назад.

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

Итак, я начал исследовать способы защиты API в целом и начал лучше понимать, как это сделать. Наиболее популярным способом, по-видимому, является отправка запросов в API вместе с контрольной суммой из всего сообщения (закодированного с секретом, который знают только вы и сервер), который сервер может использовать, чтобы решить, было ли сообщение был подделан на пути от клиента, вот так:

  1. Клиент отправляет /user.json/123?showFriends=true&showStats=true&checksum=kjDSiuas98SD987ad
  2. Сервер получает все это, ищет пользователя «123» в базе данных, загружает его секретный ключ и затем (используя тот же метод, который использовал клиент) пересчитывает свою СОБСТВЕННУЮ контрольную сумму с учетом аргументов запроса.
  3. Если сгенерированная контрольная сумма сервера и отправленная контрольная сумма клиента совпадают, запрос в порядке и выполняется, если нет, он считается подделанным и отклоненным.

Контрольная сумма называется HMAC, и если вам нужен хороший пример этого, то именно этим и пользуются Amazon Web Services (хотя они называют аргумент «подпись», а не «контрольная сумма»).

Итак, учитывая, что одним из ключевых компонентов этого для работы является то, что клиент и сервер должны генерировать HMAC одинаковым образом (в противном случае они не будут совпадать), должны быть правила, КАК объединять все аргументы ... потом я внезапно понял всю эту чушь "естественного упорядочения байтов параметров" из OAuth ... это было просто определение правил для того, как генерировать подпись, потому что это нужно.

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

Так что, если вы просто закодируете основание URI в качестве подписи, например:

  • / user.json == askJdla9 / kjdas + Askj2l8add

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

В качестве альтернативы, даже если вы включите КАЖДЫЙ параметр в расчет, вы все равно рискуете «переиграть атаки», когда злонамеренный посредник или перехватчик может перехватить вызов API и просто продолжать отправлять его на сервер снова и снова.

Это можно исправить, добавив метку времени (всегда используйте UTC) в расчет HMAC.

НАПОМИНАНИЕ: так как серверу необходимо вычислить тот же HMAC, вы должны отправить любое значение, которое вы используете в вычислениях, КРОМЕ КЛЮЧЕВОГО СЕКРЕТА (я думаю, что OAuth называет его consumer_secret). Поэтому, если вы добавляете метку времени, обязательно отправьте параметр метки времени вместе с вашим запросом.

Если вы хотите обезопасить API от атак воспроизведения, вы можете использовать одноразовое значение (это одноразовое значение, которое сервер генерирует, передает клиенту, клиент использует его в HMAC, отправляет запрос обратно сервер подтверждает, а затем помечает это одноразовое значение как «использованное» в БД и никогда не позволяет другому запросу использовать его снова).

ПРИМЕЧАНИЕ: «nonce» - это действительно точный способ решения проблемы «атаки с повторением» - временные метки хороши, но поскольку компьютеры не всегда имеют синхронизированные значения временных меток, необходимо разрешить приемлемое окно в серверная часть того, насколько «старым» может быть запрос (скажем, 10 минут, 30 минут, 1 час .... Amazon использует 15 минут), прежде чем мы примем или отклоним его. В этом случае ваш API технически уязвим в течение всего времени.

Я думаю, что одноразовые значения хороши, но их нужно использовать только в тех API, которые критически важны, поскольку они сохраняют свою целостность. В моем API мне это не нужно, но было бы просто добавить позже, если бы пользователи этого требовали ... Мне буквально просто нужно добавить таблицу «nonce» в моей БД, предоставить новый API для таких клиентов, как:

  • / nonce.json

и затем, когда мне отправят это обратно в подсчете HMAC, мне нужно будет проверить БД, чтобы убедиться, что она никогда не использовалась до этого и не использовалась, пометить ее как таковую в БД, так что, если когда-либо поступил запрос снова с тем же самым nonce я бы отклонил его.

Резюме

В любом случае, короче говоря, все, что я только что описал, это , в основном , что известно как "двуногий OAuth". Не существует этого дополнительного этапа передачи полномочий (Twitter, Facebook, Google и т. Д.) Для авторизации клиента, этот шаг удаляется, и вместо этого сервер неявно доверяет клиенту, если отправляемые им HMAC совпадают. Это означает, что у клиента есть правильный secret_key и он подписывает свои сообщения, поэтому сервер доверяет ему.

Если вы начнете искать в Интернете, этот метод кажется предпочтительным для защиты методов API в настоящее время или что-то в этом роде. Amazon почти точно использует этот метод, за исключением того, что он использует немного другой метод комбинирования для своих параметров, прежде чем подписать все это для создания HMAC.

Если вам интересно, я записал весь этот путь и мыслительный процесс, пока я его изучал. Это может помочь в организации экскурсии по этому процессу.

0 голосов
/ 29 марта 2010

Я бы сделал шаг назад и подумал о том, что отправит вам должным образом аутентифицированный клиент.

Можете ли вы хранить ключи и учетные данные в общей базе данных, которая доступна из обоих наборов сервисов, и просто внедрить OAuth-провайдера на одном языке? Когда пользователь отправляет запрос в службу (PHP или Java), вы проверяете общий магазин. Когда пользователь настраивает клиент OAuth, вы делаете все это через приложение PHP или Java (по своему усмотрению) и сохраняете учетные данные в общей БД.

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

...