Страницы

Поиск по вопросам

вторник, 5 марта 2019 г.

Как правильно хранить сессию при разработке JSON API?

Обычно мы храним id сессии в cockie браузера. Но допустим я хочу использовать свое API в мобильных приложениях ios/android, и я собираюсь хранить куку в памяти приложения и вставлять потом в каждый запрос с приложения. Но на сколько это правильно? Есть ли какие-то советы по этому поводу?


Ответ

Но на сколько это правильно?
Тут просто нет другого подхода. Вам так или иначе надо идентифицировать пользователя API. По каким-либо косвенным признакам вы его идентифицировать не можете - на одном IP могут сидеть несколько потребителей, User-Agent нет в принципе, да и вообще это просто подменяемый заголовок и не более.
Поэтому вам надо с каждым запросом передавать некий идентификатор, который сможет помочь вам найти пользователя. Тут есть несколько тонких моментов:
Это не должен быть сам идентификатор пользователя (иначе весь механизм ломается через угон идентификатора, и с угнанным пользователем нельзя сделать ничего, кроме его убийства) Этот идентификатор (или механизм, связанный с ним) должен однозначно подтверждать корректность сессии либо передаваться исключительно по защищенному каналу (HTTPS), иначе его можно будет ровно так же угнать и представляться некорректным пользователем. Идентификаторы должны считаться расходным материалом в приложении: их всегда можно грохнуть и насоздавать новых, чтобы любой угнанный идентификатор мог быть обнулен сразу после обнаружения угона
Общепринятым подходом считается передаче токена доступа в произвольном заголовке (github, google, amazon s3). Так или иначе информация для аутентификации всегда остается в заголовках (в query parameters и непосредственно теле запроса ей не место), поэтому здесь на самом деле тоже особого выбора нет. Токен хранится на устройстве, в случае паники пользователь удаляет токен (пользуясь тем же токеном доступа)
Последний абзац - про подтверждение корректности сессии, передаваемое по незащищенному каналу. В случае, если есть опасения за перехват токена при его передаче - необходимо так или иначе подписывать исходящие запросы. Для этого можно использовать полновесную или легковесную challenge-response аутентификацию, смысл которой можно свести к тому, что сервер и клиент загадывают друг другу загадки, которые могут разгадать только они сами. В самом простом варианте сервер может выписывать токен, состоящий из идентификатора и секретной части (ключа шифрования), которая однократно передается клиенту при создании токена (клиент тоже может при этом переать некий секрет, но мы считаем, что серверу всегда можно доверять). После этого все сообщения от клиента к серверу либо полностью шифруются полученным ключом, либо содержат в дополнительном заголовке сформированную на основе ключа и тела запроса подпись, которую злоумышленник не сможет подделать, не своровав секретный ключ. Это, однако, не защищает само по себе от:
Replay-атак (e.g. если пользователь шлет запрос "удалить последнюю запись", то злоумышленник может сгенерировать еще сотню таких запросов и полностью очистить историю пользователя). Самое простое решение - жонглирование временными метками (e.g. не принимать запросы старше 5 секунд), но при малейших проблемах с синхронизацией стреляет в ногу. Физического изъятия ключа у клиента. Обычно считается, что от этого нельзя защититься, и этот момент просто игнорируется. Перехвата ключа в момент выписывания токена (поэтому лучше все-таки обзавестись HTTPS). При открытом трафике можно воспользоваться алгоритмом Диффи-Хеллмана и аналогами, но это займет времени больше, чем написание самого приложения. Вычисления ключа при использовании некорректного алгоритма (e.g. если не происходит ротации ключа и если злоумышленник знает, что всегда используется JSON, то он, зная, что последний символ всегда является } или ], может вычислить ключ, сравнивая запросы разной длины). Опять же, проще взять HTTPS, есть альтернативные методы, но я не буду их рассказывать, чтобы ненароком не пропустить важный момент.
upd. есть некий стандарт json web token, сам я с ним пока не ознакомился.

Комментариев нет:

Отправить комментарий