Как получить куки из браузера python

Обновлено: 25.06.2024

Ранее модуль строго применял правила парсинг, описанные в спецификациях RFC 2109 и RFC 2068. С тех пор было обнаружено, что MSIE 3.0x не соблюдает правила символ, изложенные в этих specs, а также многие браузеры и серверы текущего дня смягчили правила парсинг, когда дело доходит до обработки cookie. В результате парсинг постановляет, что используемый немного менее строги.

: обозначают набор допустимых символов, разрешенных этим модулем в имени cookie (как key ).

Изменено в версии 3.3: Допускается «»: «» в качестве допустимого имени cookie символ.

Ошибка исключения из-за недействительности RFC 2109: неправильная атрибуты, неправильный заголовок Set-Cookie и т.д.

Этот класс - подобный словарю объект, ключи которого - строки и чьи значения - Morsel сущности. Обратите внимание, что после устанавливания ключа к значение, значение сначала преобразован в Morsel , содержащий ключ и значение.

Если задано значение input, оно передается методу load() .

Объекты cookie¶

Возвращает кортеж (real_value, coded_value) из представления строка. real_value может быть любого типа. Этот метод не декодирует в BaseCookie — он существует, поэтому его можно переопределить.

BaseCookie. value_encode ( val ) ¶

Возвращает кортеж (real_value, coded_value) . val может быть любого типа, но coded_value всегда будет преобразован в строка. Этот метод не имеет кодировка в BaseCookie —, поэтому его можно переопределить.

В целом, должно быть так, что value_encode() и value_decode() являются обратными на диапазон value_decode.

BaseCookie. output ( attrs=None, header='Set-Cookie:', sep='\r\n' ) ¶

BaseCookie. js_output ( attrs=None ) ¶

Значение для attrs такое же, как и в output() .

BaseCookie. load ( rawdata ) ¶

Объекты Морселя¶

Абстрагируем пару ключ/значение, которая имеет некоторые RFC 2109 атрибуты.

Морсели - словареподобные объекты, набор ключей которых является постоянным — действительных RFC 2109 атрибуты, которые являются

Параметр атрибут samesite указывает, что обозревателю запрещено отправлять файлы cookie вместе с межузловыми запросами. Это помогает смягчить атаки CSRF. Действительные значения для этого атрибут «Строги» и «Слабы».

Ключи без учета регистра и их дефолт, значение - '' .

Изменено в версии 3.5: __eq__() теперь учитывает key и value .

Изменено в версии 3.7: Атрибуты key , value и coded_value доступны только для чтения. Используйте set() для их настройки.

Изменено в версии 3.8: Добавлена поддержка samesite атрибут.

Кодированный значение файла cookie — это то, что должно быть отправлено.

Задайте key, value и coded_value атрибуты.

Morsel. isReservedKey ( K ) ¶

Является ли K членом набора клавиш Morsel .

Morsel. output ( attrs=None, header='Set-Cookie:' ) ¶

Morsel. js_output ( attrs=None ) ¶

Значение для attrs такое же, как и в output() .

Morsel. OutputString ( attrs=None ) ¶

Значение для attrs такое же, как и в output() .

Morsel. update ( values ) ¶

Обновите значения в словаре Морселя с помощью значения в словаре values. Вызовите ошибку, если любой из ключей в values словарь не является допустимым RFC 2109 атрибут.

Получение данных из форм

Итак, во-первых разберёмся с формами. В модуле CGI есть полезный класс: FieldStorage, который содержит в себе переданную в форме информацию. По сути дела этот класс представляет из себя словарь, обладающий теми же свойствами, что и обычный словарь в python.

У класса FieldStorage есть 2 метода получения значений данных формы:

FieldStorage.getfirst(name, default=None) - всегда возвращает только одно значение, связанное с именем поля формы. Метод возвращает только первое значение в том случае, если нехороший пользователь послал более одного значения. Обратите внимание, что порядок, в котором будут получены значения, могут отличаться от браузера к браузеру. Если нет такого поля формы или значение не существует, то метод возвращает default.

FieldStorage.getlist(name) - возвращает список значений, связанных с именем поля формы.

Разберём на примере: создадим в нашей папке файл index.html со следующим содержимым (это будет наша форма, данные из которой мы будем обрабатывать):

А в папке cgi-bin/ - файл form.py (обработчик формы)

Попробуем это в действии (кто сидит на linux, не забудьте поставить права на выполнение).

Запускаем локальный сервер, и переходим на localhost:8000:

Но есть нюанс.

А если попробовать так?

Это серьёзная уязвимость, поэтому от неё нужно избавляться. Для этого нужно (в самом простом случае) экранировать все опасные символы. Это можно сделать с помощью функции escape из модуля html.

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

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

Cookies

Отправка печенек осуществляется заголовком Set-cookie:

Все эти параметры не являются обязательными. Можно написать так:

Обработка Cookies

Напишем простой скрипт (/cgi-bin/cookie.py), проверяющий, установлена ли кука, и если нет, устанавливает:

Так страница выглядит после первого запроса:

И после обновления страницы:

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

В этой статье мы сосредоточимся в основном на технической стороне. Вы узнаете, как создавать, использовать и работать с файлами куки как во фронтенде, так и в бэкенде.

Содержание

Настройка бэкенда

Примеры для бэкенда сделаны при помощи Python и его фреймворка Flask. Если вы хотите воспроизводить код из данной статьи, создайте новую виртуальную среду Python и установите Flask.

В каталоге проекта создайте файл flask_app.py и используйте наши примеры для собственных экспериментов.

Перво-наперво надо выяснить, откуда берутся куки и кто их создает.

Хотя с помощью свойства document.cookie можно создавать куки непосредственно в самом браузере, в большинстве случаев за их установку отвечает серверная часть (бэкенд).

Под этим мы подразумеваем, что куки создаются:

  • реальным кодом приложения, которое работает на сервере и может быть написано на языках Python, JavaScript, PHP, Java и др.
  • самим веб-сервером, отвечающим на запросы (Nginx, Apache)

Когда и где создавать эти файлы куки, зависит от соответствующих требований.

Итак, куки это просто строки. Рассмотрим пример с Python и Flask. Сохраните следующий код в файл flask_app.py , который вы создали в директории проекта.

Затем запустите приложение:

Заголовок Set-Cookie имеет ключевое значение для понимания того, как создавать куки.

Большинство фреймворков имеют собственные служебные функции для программной установки файлов куки. Во Flask, например, эта функция называется set_cookie() .

Под капотом такие функции в ответ на запрос просто устанавливают заголовок с Set-Cookie .


Или проверьте вкладку Storage в инструментах разработчика. Нажмите на Cookies , и вы должны увидеть файл куки:

Также можно использовать команду curl в командной строке. Вы увидите, какие файлы куки были установлены бэкендом.

Чтобы сохранить куки в новый файл для дальнейшего использования, воспользуйтесь следующей командой:

Для того чтобы вывести куки в консоль, наберите вот эту команду:

Теперь куки по-прежнему будут отображаться на вкладке Cookie Storage , но document.cookie вернет пустую строку.

С этого момента для удобства мы будем создавать куки при помощи функции response.set_cookie() из фреймворка Flask.

Проверять файлы куки мы будем тремя способами:

  • командой curl
  • при помощи инструментов разработчика (developer tools) браузера Firefox
  • при помощи инструментов разработчика (developer tools) браузера Chrome.

Марк Лутц «Изучаем Python»

Скачивайте книгу у нас в телеграм

Ваш браузер получил куки. И что теперь? Если у вас есть куки, браузер может отправлять их обратно на серверную часть.

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

При авторизации на сайте сервер может предоставить вам вот такой кук:

Чтобы правильно идентифицировать вас при каждом последующем запросе, бэкенд проверяет кук, поступающий из браузера в запросе.

Куки имеют срок давности. Атрибуты Max-Age и expires

По умолчанию срок действия куков истекает, когда пользователь завершает сеанс, то есть когда он закрывает браузер. Чтобы сохранить куки, мы можем передать атрибуты expires или Max-Age :

Когда присутствуют оба атрибута, Max-Age имеет приоритет над expires .

Cookies, ограниченные атрибутом Path

Запустим наше приложение:

В другом терминале, установив соединение с корневым маршрутом (root), мы увидим вот такой кук в Set-Cookie :

Обратите внимание, что у кука есть атрибут Path :

Теперь давайте посетим маршрут /about/ , отправив кук, который мы сохранили при первом посещении:

В терминале, где запущено приложение Flask, вы должны увидеть следующее:

Как и ожидалось, кук возвращается на серверную часть. Теперь попробуйте посетить страницу /contact/ :

На этот раз в терминале, где запущено приложение Flask, вы должны увидеть вот что:

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

Это первый уровень разрешений для куков.

Cookies, ограниченные атрибутом Domain

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

Давайте рассмотрим несколько примеров.

ПРИМЕЧАНИЕ: следующий URL-адрес находится на бесплатном сервере Heroku. Поэтому дайте ему немного времени, чтобы он набрал обороты и после этого откройте консоль браузера.

Несоответствующий хост (неправильный адрес хоста)

У браузеров нет другого выбора, кроме как отклонить данный кук. Chrome даже выдаст предупреждение (в отличии от Firefox):


Несоответствующий хост (поддомен)

Они находятся в одном домене, но поддомены отличаются. И снова браузер отклоняет такой кук:


Соответствующий хост (весь домен)

Этот кук устанавливается на уровне веб-сервера при помощи Nginx add_header :

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

Здесь браузер с радостью примет кук, потому что хост в Domain включает в себя хост, с которого пришел сам кук.

Вот запрос к поддомену с прикрепленным куком:


А вот запрос к другому поддомену с автоматически прикрепленным куком:


Куки и список общедоступных суффиксов

Но вместо этого он отклонит данный кук, поскольку тот поступает из домена, включенного в список общедоступных суффиксов.

Public Suffix List поддерживается Мозиллой и используется всеми браузерами для ограничения установки куков от имени других доменов.

Соответствующий хост (поддомен)

Если при создании кука домен не указан, браузеры по умолчанию используют исходный хост в адресной строке. В этом случае наш код будет иметь следующий вид:

Когда кук попадает в хранилище браузера для куков, мы видим, что домен был указан:




Напомним, как браузер решает, что делать с куками. Здесь под хостом отправителя мы подразумеваем фактический URL-адрес, который вы посещаете.

  • Полностью отклоняет кук, если домен или поддомен в атрибуте Domain не соответствуют хосту отправителя.
  • Отклоняет кук, если значение домена включено в список общедоступных суффиксов.
  • Принимает кук, если домен или поддомен в атрибуте Domain совпадает с хостом отправителя.

Когда браузеры принимают куки и собираются сделать запрос, они говорят:

Рассмотрим еще один пример с Flask. У нас есть шаблон, который загружает файл JavaScript. Вот приложение Flask:

Вот шаблон из файла templates/index.html :

Вот JavaScript-код из файла static/index.js :

Теперь давайте немного изменим наше приложение Flask:

Кроме того, давайте немного подстроим наш код JavaScript, чтобы сделать еще один Fetch -запрос после получения кука:

В консоли браузера вы должны увидеть массив городов. Кроме того, на вкладке Network инструментов разработчика вы должны увидеть заголовок с именем кука, передаваемого в бэкэнд по запросу AJAX.


Этот обмен куками между интерфейсом и серверной частью работает нормально, пока интерфейс находится в одном контексте с серверной частью: мы говорим, что они находятся в одном источнике.

Это потому, что по умолчанию Fetch отправляет учетные данные, то есть куки, только тогда, когда запрос попадает в тот же источник, из которого он запускается.

А теперь давайте посмотрим, что происходит при разных источниках.

Cookies не всегда могут передаваться по запросам AJAX

Рассмотрим другую ситуацию, когда серверная часть работает автономно. Итак, у вас запущено следующее приложение Flask:

Теперь в другой папке, вне приложения Flask, создайте файл index.html :

Создайте в той же папке файл JavaScript с именем index.js со следующим кодом:

В этой же папке из терминала запустите команду npx serve .

Работа с CORS

Далее применим CORS к нашему коду:

Теперь попробуйте еще раз нажать кнопку с открытой консолью браузера. В консоли вы должны увидеть следующее:

Несмотря на то, что мы получили ту же ошибку, на этот раз виноват второй маршрут.

К запросу не прикреплен кук с именем «id», поэтому Flask аварийно завершает работу и не устанавливает Access-Control-Allow-Origin .

В этом можно убедиться, посмотрев запрос во вкладке Network (в инструментах разработчика). Такие куки не отправляются:


credentials: "include" должен присутствовать в первом Fetch-запросе, чтобы сохранить кук в хранилище.

Он также должен присутствовать во втором запросе, чтобы разрешить передачу куков обратно в серверную часть:

Теперь вы должны увидеть ожидаемый массив городов в консоли браузера.

  • credentials: "include" во фронтенде для Fetch-запроса
  • Access-Control-Allow-Credentials и Access-Control-Allow-Origin в бэкенде.

Куки могут передаваться по запросам AJAX, но они должны соответствовать доменным правилам, которые мы здесь описали.

Конкретный пример

В нашем предыдущем примере использовался localhost, чтобы все было просто и воспроизводимо на вашем локальном компьютере.

Чтобы представить обмен куками по запросам AJAX в реальном мире, вы можете наметить себе следующий сценарий:

Куки могут иметь своего рода секрет: атрибут Secure

Но этот секрет не такой уж и секретный, по большому счету.

Чтобы пометить кук как безопасный, передайте в него соответствующий атрибут:

В коде сервера Flask:

Примечание: это будет работать только в версии curl >=7.64.0, который реализует rfc6265bis. Более старые версии curl реализуют RCF6265.

Вот как оно выглядит:

Чтобы проверить куки в браузере, посетите обе версии указанного выше URL-адреса и проверьте хранилище куков в инструментах разработчика.

Не обманывайтесь самим словом Secure (безопасный). Куки придут к вам по безопасному соединению, но после того как они окажутся в вашем браузере, никакой защиты у них не будет.

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

В сервере Flask:

Зловещий атрибут SameSite

Собственные и сторонние куки

Мы называем этот вид куков собственными. То есть, если я посещаю этот URL-адрес в браузере, и если я посещаю тот же URL-адрес или другую страницу на этом сайте (при условии, что атрибут Path установлен в значение / ), то браузер отправляет куки обратно на сайт. Обычные куки, одним словом.

Этот сторонний ресурс, в свою очередь, сам устанавливает свои куки. Вы можете увидеть этот сценарий на скрине ниже:


Примечание: если вы используете Chrome 85, вы не увидите этот кук. Начиная с этой версии Chrome отклоняет его. Мы называем этот вид куков сторонними. Другой пример стороннего кука:

Работа с атрибутом Samesite

На момент написания данной статьи сторонние куки вызывают всплывающее окно с предупреждением в консоли Chrome:

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

Атрибуту SameSite может быть присвоено одно из трех значений:

Если мы являемся службой, предоставляющей встраиваемые виджеты (iframe), или нам необходимо размещать куки на удаленных веб-сайтах (по уважительной причине, а не для дикого отслеживания), эти куки должны быть помечены как SameSite=None и Secure :

В противном случае браузер отклонит сторонний кук. Вот что браузеры собираются делать в ближайшем будущем:

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

Стоит отметить, что атрибут SameSite относится не только к сторонним кукам.

По умолчанию браузеры будут применять SameSite=Lax для всех куков, как собственных, так и сторонних, если данный атрибут отсутствует. Вот какая политику у браузера Firefox Nightly относительно собственных куков:

Сторонние куки с атрибутом SameSite=Strict будут полностью отклоняться браузером.

Напомним, вот поведение браузера для разных значений SameSite :

Чтобы узнать больше о SameSite и подробно разобраться во всех вариантах использования этого атрибута, почитайте эти отличные ресурсы:

Куки и аутентификация

Посмотрим, какую роль здесь играют куки.

Аутентификация на основе сессий

Когда вы посещаете сайт, запрашивающий аутентификацию, то при отправке учетных данных (например, через форму) бэкенд отправляет фронтенду заголовок Set-Cookie .

Типичный кук сессии выглядит следующим образом:

В этом заголовке Set-Cookie сервер может включать кук с именем session , session id или аналогичный.

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

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

Аутентификация на основе сессий представляет из себя отслеживание состояний, поскольку серверная часть должна отслеживать сессии для каждого пользователя. Хранилищем для этих сессий может быть:

  • база данных
  • хранилище ключей / значений, такое как Redis
  • файловая система.

Из этих трех хранилищ сессий предпочтение следует отдавать Redis (или ему подобным).

Обратите внимание, что аутентификация на основе сессий не имеет ничего общего с хранилищем сессий браузера.

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

Когда использовать аутентификацию на основе сессий?

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

Замечание по поводу JWT

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

  1. Фронтенд отправляет учетные данные бэкенду.
  2. Бэкенд проверяет учетные данные и отправляет обратно токен.
  3. Фронтенд отправляет токен при каждом последующем запросе.

Главный вопрос, который возникает при таком подходе: где нам хранить этот токен во фронтенде, чтобы пользователь оставался авторизованным?

Самым естественным поступком для того, кто пишет на JavaScript, является сохранение токена в localStorage . Это плохо по многим причинам.

localStorage легко доступен из кода JavaScript и является легкой мишенью для XSS-атак.

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

Заключение

Кук может использоваться для персонализации взаимодействия с пользователем, аутентификации пользователей или для скрытых целей, таких как отслеживание.

Но при любом предполагаемом использовании куки могут открывать пользователей для атак и уязвимостей.

Так что же может сделать куки безопасными? Это просто невозможно. Мы можем считать их относительно безопасными, если они:

Common Gateway Interface, или CGI, представляет собой набор стандартов, определяющих, как происходит обмен информацией между веб-сервером и пользовательским сценарием. Спецификации CGI в настоящее время поддерживаются NCSA.

Что такое CGI?

Просмотр веб-страниц

Чтобы понять концепцию CGI, давайте посмотрим, что происходит, когда мы нажимаем гиперссылку для просмотра определенной веб-страницы или URL-адреса.

Диаграмма архитектуры CGI

Поддержка и настройка веб-сервера

Здесь мы предполагаем, что ваш веб-сервер запущен и работает успешно, и вы можете запустить любую другую программу CGI, такую ​​как Perl или Shell и т. Д.

Первая программа CGI

Вот простая ссылка, которая связана с CGI-скриптом, который называется hello.py . Этот файл хранится в каталоге / var / www / cgi-bin и имеет следующий контент. Перед запуском программы CGI убедитесь, что у вас есть режим изменения файла, используя команду UNIX chmod 755 hello.py, чтобы сделать файл исполняемым.

Введите следующий URL в вашем браузере

Этот сценарий hello.py представляет собой простой сценарий Python, который записывает свой вывод в файл STDOUT, то есть на экран. Существует одна важная и дополнительная функция, которая должна быть напечатана в первой строке. Тип содержимого: text / html \ r \ n \ r \ n . Эта строка отправляется обратно в браузер и указывает тип контента, который будет отображаться на экране браузера.

К настоящему времени вы, должно быть, уже поняли основную концепцию CGI, и вы можете писать много сложных CGI-программ, используя Python. Этот сценарий может взаимодействовать с любой другой внешней системой также для обмена информацией, такой как СУБД.

Тип содержимого:

Строка MIME, определяющая формат возвращаемого файла. Примером является Content-type: text / html

Истекает: Дата

Дата, когда информация становится недействительной. Он используется браузером, чтобы решить, когда необходимо обновить страницу. Допустимая строка даты в формате 01 января 1998 12:00:00 по Гринвичу.

Расположение: URL

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

Дата последней модификации ресурса.

Длина содержимого: N

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

Набор Cookie: Строка

Установить куки, пропущенные через строку

Тип содержимого:

Строка MIME, определяющая формат возвращаемого файла. Примером является Content-type: text / html

Истекает: Дата

Дата, когда информация становится недействительной. Он используется браузером, чтобы решить, когда необходимо обновить страницу. Допустимая строка даты в формате 01 января 1998 12:00:00 по Гринвичу.

Расположение: URL

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

Дата последней модификации ресурса.

Длина содержимого: N

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

Набор Cookie: Строка

Установить куки, пропущенные через строку

Переменные среды CGI

Все программы CGI имеют доступ к следующим переменным среды. Эти переменные играют важную роль при написании любой CGI-программы.

ТИП СОДЕРЖИМОГО

Тип данных контента. Используется, когда клиент отправляет вложенный контент на сервер. Например, загрузка файла.

CONTENT_LENGTH

Длина запроса информации. Он доступен только для запросов POST.

Возвращает установленные куки в виде пары ключ-значение.

Поле заголовка запроса User-Agent содержит информацию о пользовательском агенте, создавшем запрос. Это имя веб-браузера.

Путь для скрипта CGI.

СТРОКА ЗАПРОСА

Информация в кодировке URL, отправляемая с запросом метода GET.

REMOTE_ADDR

IP-адрес удаленного хоста, отправляющего запрос. Это полезно для ведения журнала или для аутентификации.

УДАЛЕННЫЙ УЗЕЛ

Полное имя хоста, сделавшего запрос. Если эта информация недоступна, тогда REMOTE_ADDR может использоваться для получения IR-адреса.

REQUEST_METHOD

Метод, использованный для запроса. Наиболее распространенными методами являются GET и POST.

Читайте также: