Как вы защищаете RESTful API, используемый браузером, от CSRF-атак? - PullRequest
11 голосов
/ 21 ноября 2011

Я разрабатываю API для группы сайтов. Сайты очень похожи (вроде StackOverflow, SuperUser и ServerFault), и для них имеет смысл иметь общий бэкэнд. Поэтому мы решили попробовать использовать хороший REST API в качестве бэкэнда и множество очень похожих, но разных внешних интерфейсов, потребляющих указанный API. Желательно, чтобы все интерфейсы были статичными, но это не является жестким требованием, если оно оказывается невозможным.

Сейчас я работаю над созданием этого API и беспокоюсь о последствиях для безопасности, особенно о CSRF. Исходя из моего базового понимания атак CSRF, они состоят из двух важных компонентов:

  1. Возможность назвать ресурс и тело запроса.

  2. Обман пользователя / браузера с помощью ambient auth (например, сессий), чтобы сделать запрос к тому ресурсу, который выглядит аутентифицированным.

Многие классические подходы к исправлению CSRF-атак основаны на сеансе. Поскольку мой REST API на самом деле не выполняет сессий, это предотвращает множество векторов, а также практически все способы их устранения. Например, двойная отправка не имеет смысла, потому что нечего дважды отправлять.

Мой первоначальный подход включал атаку второй части атаки CSRF. Если я аутентифицирую все запросы (скажем, с использованием HTTP Basic Auth), и браузер не сохраняет эти учетные данные сохраненными (например, некоторые JS сделали запрос), только JS, имеющий учетные данные, может выполнить запрос, и мы закончили , Очевидным недостатком является то, что приложение должно знать учетные данные пользователя. Другой чуть менее очевидный недостаток - то, что если я хочу надежно хранить учетные данные на стороне API, то проверка пароля должна занять фиксированное, нетривиальное время. Если для безопасной проверки пароля требуется 100 мс, то для каждого другого запроса потребуется не менее 100 мс + eps, и потребуется несколько хитроумных хитрых хитростей на стороне клиента, чтобы это не казалось медленным. Я мог бы кешировать это (так как учетные данные всегда будут одинаковыми), и если я буду очень осторожен, мне удастся сделать это без введения временной уязвимости, но это звучит как гнездо шершня.

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

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

Я также рассмотрел возможность атаки на точку 1, сделав URL-адреса рандомизированными, то есть добавив токены в строку запроса. Это, безусловно, сработает, и это очень близко к тому, как работает традиционный рандомизированный токен в форме, и, учитывая HATEOAS, он даже должен быть довольно RESTful, хотя возникает два вопроса: 1) с чего начать? Есть ли обязательная точка запуска API, в которой вы входите в систему с использованием HTTP Basic Auth? 2) Сколько бы обрадовали разработчики приложений, если они не могут заранее предсказать URL, черт побери HATEOAS?

Я видел Как предотвратить CSRF в приложении RESTful? , но я не согласен с предположением, что рандомизированные URI обязательно не являются RESTEST. Кроме того, этот вопрос на самом деле не имеет удовлетворительных ответов и не упоминает OAuth. Кроме того, решение для двойной отправки сеанса недопустимо, как я упоминал выше (другой домен для статического внешнего интерфейса, чем конечная точка API).

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

Ответы [ 4 ]

3 голосов
/ 21 ноября 2011

Маркер CSRF по определению "для каждого пользовательского состояния" и, следовательно, не RESTful. Большинство API нарушают свои требования "для каждого пользовательского состояния" в целях безопасности и требуют, чтобы токен CSRF передавался как параметр заголовка HTTP.

Существуют и другие способы предотвращения CSRF . Проверка реферера не так сильна, как токен CSRF, но это RESTful и VERY вряд ли будет подорвано. Имейте в виду, что отсутствие реферера следует считать неудавшимся запросом.

XSS может использоваться для обхода как предотвращения CSRF на основе токенов, так и предотвращения CSRF на основе реферера.

0 голосов
/ 23 февраля 2013

Разработка вашего API как истинного RESTful, предотвращает наиболее распространенные векторы CSRF:

  • избегание файлов cookie предотвращает их «кражу»,
  • использование GET для «безопасных» операций запрещает img и iframes запускать небезопасные действия без взаимодействия с пользователем.

Затем вы должны внедрить CORS , чтобы позволить браузерам пользователей блокировать запросы от источников, которым вы не доверяете.

0 голосов
/ 22 ноября 2011

У меня есть другое потенциальное решение, поэтому я перечисляю его как ответ.Пожалуйста, не стесняйтесь разбирать его:)

auth.platform.com берет аутентификацию и устанавливает куки.Если auth.site.com является CNAME для auth.platform.com, сможет ли запрос к auth.site.com (заканчивающийся на auth.platform.com после разрешения) установить cookie для site.com?Таким образом, я мог бы дважды отправить сеансовые куки.

Конечно, auth.platform.com будет устанавливать куки только для нескольких доменов из белого списка.

РЕДАКТИРОВАТЬ: За исключением, конечно, это не будет работать вообщепотому что вам придется использовать HTTPS для безопасной аутентификации, и HTTPS увидит ваши хитрости.

0 голосов
/ 21 ноября 2011

Ответ зависит от того, что вам нужно поддержать. Если мы предполагаем, что вы хотите поддерживать веб-приложение, которое использует службу REST, и использовать ту же службу REST для API, который отличается от веб-приложения, которое оказывается RESTFUL (вы можете решить, что «сессии» для вас!).

На данный момент (/ я довольно устал), я думаю, то, что вы предложили использовать javascript с HTTP Basic Auth, является хорошим началом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...