Печенья, кеки, кукисы, ку-ку, кексы… нет, куки!Cookie — это что?
Почему их не нужно принимать?
Безопасно ли это?
CookieJar, CookieManager, CookieStore… WebView?
А также истории про то, как жить с cookie в большом приложении, и сколько эмоций вы испытаете, если в вашем приложении есть WebView.
За техническую консультацию (и моральную поддержку при работе с cookie на Android) спасибо Сергею Мазулеву и Максиму Шестоперову, команда OzonID.
За консультацию по юридическим вопросам спасибо Михаилу Ратушному, руководителю практики защиты персональных данных Ozon.
Cookie — они зачем?
Сначала определим, из чего состоят cookie и для чего используются. В общем смысле, не только на Android.
В большинстве случаев их удобно использовать для передачи:
токенов авторизации;
флагов с бэка на мобилку;
параметров устройства с мобилки на бэк.
Но зашить можно любую информацию, ограничений нет. Например, можно удобно организовать авторизацию:
1. пользователь вводит логин и пароль;
2. бэкенд авторизует юзера и присылает в ответ cookie-токен;
3. клиент начинает отсылать в cookie-токен на все следующие запросы.
Готово, бэкенд знает, от какого пользователя летят запросы.
Как выглядят cookie?
Cookie — это строка, состоящая из:
ключа;
значения;
атрибутов.
Ключ и значение могут быть произвольные. Атрибуты заранее определены, но при этом все они опциональны — можно присылать только нужные.
Например,
Cookie передаются как один из header (заголовков) http(s)-запроса. Причем как с клиента на бэкенд, так и в обратную сторону.
Cookie == Header?
Да, cookie передаётся в списке хедеров, как и все остальные хедеры (например, user-agent).
Но есть отличие: cookie автоматически прикрепляются к домену (см. атрибут domain) и начинают отсылаться в каждом запросе на этот domain (хост).
Например, с домена ozon.ru бэк прислал cookie userId = 123. Это значит, что в следующий запрос на ozon.ru автоматически добавится header с этой же cookie userId = 123. И она будет улетать, пока не протухнет (см. Session vs Permanent Cookie) или не будет перезаписана устройством или новой cookie userId = 456 с бэкенда.
Будьте осторожны со значениями — если положить строку, содержащую символ точки с запятой «;» или запятой «,», некоторые клиенты могут неправильно распарсить cookie.
Почему приложения не спрашивают у нас разрешения?
Уверен, где-нибудь в интернете есть коллекция всех вариаций запроса на работу с cookie на web-сайтах…
Но почему подобный запрос не вылазит в каждом приложении?
Важно: не является истиной в последней инстанции. Если вы Большая компания — проконсультируйтесь с юристом 😉
Важноx2: речь идет про РФ. В вашей местности всё может быть совсем по-другому 😉
Общее правило:
явно запрашивать у пользователя разрешение на передачу cookie нужно, если они не являются технически необходимыми для работы приложения.
Например, запрашивать разрешение
не нужно: в cookie передаются токены авторизации пользователя, которые используются только внутри компании;
нужно: в cookie передаются рекламные идентификаторы, передаваемые другим компаниям.
Где почитать подробнее:
РФ — Федеральный закон № 152-ФЗ «О персональных данных»
GDPR
ePrivacy Directive
В приложении Ozon мы не запрашиваем разрешение на cookie. А на сайте даём пользователю выбор:
Как передаются Cookie
Cookie передаются в хедерах http-запросов в обе стороны: от бэка на мобилку и с мобилки на бэк.
бэк присылает cookie в заголовке с name = Set Cookie, они прикрепляются к domain;
Android-приложение при формировании запроса на domain находит прикрепленные к нему cookie и отсылает их в заголовке name = Cookie.
Также создать cookie и прикрепить их к domain можно локально через CookieManager.put(…). Но в этом случае необходимо самостоятельно следить за их жизненным циклом, не перепутать домены и не забыть про атрибуты.
В каждом запросе (и ответе) может быть несколько заголовков Cookie (Set Cookie).
Session vs Permanent Cookie
Permanent — если передать атрибут expiresIn (max-age), то cookie будут жить в памяти, пока не протухнут;
Session — если не передавать атрибут expiresIn (max-age), то cookie будут жить в памяти, пока не прервётся соединение (например, не будет перезагружено приложение).
Это описание стандартного поведения. Его, например, реализует CookieHandler.getDefault() (что это за класс — рассмотрим ниже).
Вам, конечно, никто не помешает сохранить cookie в ПЗУ навсегда или стереть их в любой момент.
Безопасность
К cookie стоит относиться так же, как и к обычным https-запросам.
С одной стороны, это всё шифруется вместе с телом запроса, но с другой, — кому надо, тот найдет способ перехватить.
Поэтому передаём минимум чувствительной информации (пароли в открытом виде не стоит).
Как работать с cookie в Android
Нам потребуется несколько классов из стандартных библиотек:
OkHttpClient — базовый класс, настраивающий все взаимодействие с сетью;
CookieJar — DAO для работы с CookieManager;
CookieManager — DAO для работы с CookieStore;
CookieStore — хранилище кук.
Собрав цепочку из них, мы организуем хранение, управление и передачу cookie.
При этом многие из этих классов имеют стандартные реализации, переопределять которые стоит только при необходимости.