Просмотр файлов cookie, дублированных при использовании файлов cookie, восстановленных из базы данных - PullRequest
1 голос
/ 10 июля 2019

Я работаю с некоторым API, используя запросов .Чтобы сохранить свою учетную запись авторизованной, я сохраняю файлы cookie в базе данных при выходе и восстанавливаю их в следующий раз.

По некоторым причинам запросы не заменяют старые файлы cookie новыми значениями, возвращаемыми сервером.Он просто добавляет новый файл cookie с тем же именем, но с другим значением.

Код:

from requests import Session
import json

local_session = Session()
local_session.cookies.update(json.loads(account.cookies))

resp = local_session.request("GET", "http://example.com/path0/")
# all cookies have been sent, server renewed some of them and return in "Set_Cookie" headers

resp = local_session.request("GET", "http://example.com/path1/")
# here requests send two cookies with same name but different values instead of one with new

Файлы cookie в базе данных:

{
    "csrf": "abcdefgh",
    "session": "1234567890"
}

Файлы cookie, отправленные последнимизапрос:

{
    "csrf": "abcdefgh",
    "csrf": "ijklmnop",
    "session": "1234567890"
}

Что я пропустил, возможно ли это исправить разумно?


UPD.

У меня естьпробовал в консоли с httpbin и ... результат тот же, он дублирует куки:

from requests import Session

with Session() as sess:
    sess.cookies.update({"sessioncookie": "1234567890"})
    # Same behavior with sess.cookies.set('sessioncookie','1234567890')
    sess.get("https://httpbin.org/cookies/set/sessioncookie/0987654321")
    print(sess.cookies.items())
    # here's two pairs of cookies with same name now

Ответы [ 2 ]

2 голосов
/ 10 июля 2019

Cookies немного сложнее, чем просто пары ключ-значение. Браузеры также должны отслеживать, для каких URL-адресов действуют cookie-файлы (с помощью правил об именах хостов, номерах портов, путях URL-адресов и о том, будет ли соединение зашифровано) и как долго их хранить (срок действия которых истек). Некоторые файлы cookie предназначены для истечения срока действия, когда вы закрываете браузер, и поэтому срок их действия не установлен.

Однако вы не храните всю эту информацию в базе данных. Вы только сохранили ключи и значения, и когда вы затем добавляете куки в новый requests.Session() cookiejar, эти куки помечаются как универсальные и постоянные . Файлы cookie будут отправлены на все URL-адреса, срок их действия не истечет, и они никогда не будут удалены по любой причине. Этот тип куки иногда называют supercookie . Но сервер по-прежнему также устанавливает обычные файлы cookie с полной информацией о сроке действия и сроке действия URL, и из-за этих настроек они являются различными файлами cookie .

Вы можете подтвердить это, перебирая объекты cookie в вашем образце httpbin.org код:

>>> from requests import Session
>>> sess = Session()
>>> sess.cookies.update({"sessioncookie": "1234567890"})
>>> __ = sess.get("https://httpbin.org/cookies/set/sessioncookie/0987654321")
>>> for cookie in sess.cookies: print(cookie)
...
<Cookie sessioncookie=1234567890 for />
<Cookie sessioncookie=0987654321 for httpbin.org/>

Здесь есть два отдельных файла cookie: один для / (все пути, все домены) и один только для httpbin.org. Оба будут отправлены.

Вам необходимо сохранить гораздо больше информации в базе данных, чтобы воссоздать «нормальные» куки. Если вам не нужно читаемое хранилище, то библиотека requests явно делает cookiejar маринованным:

import pickle

cookiedata = pickle.dumps(session.cookies, pickle.HIGHEST_PROTOCOL)

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

session.cookies.update(pickle.loads(cookiedata))

В противном случае, если вам нужен JSON, вам придется хранить все атрибуты Cookie :

cookie_attrs = [
    "version", "name", "value", "port", "domain", "path", "secure",
    "expires", "discard", "comment", "comment_url", "rfc2109"
]
cookiedata = json.dumps([
    {attr: getattr(cookie, attr) for attr in cookie_attrs}
    for cookie in session.cookies
])

и восстановление из JSON с помощью

for entry in json.loads(cookiedata):
    session.cookies.set(**entry)

С технической точки зрения, есть также атрибут _rest, который отслеживает атрибут HttpOnly файлов cookie (во вложенном словаре), но этот атрибут в противном случае не игнорируется requests, поскольку он применяется только к браузерам, в которых файлы cookie с этот атрибут, установленный на True, недоступен из JavaScript.

В принципе, атрибуты domain, path, name делают cookie уникальным , но если сервер устанавливает, скажем, cookie с определенным значением port, и вы Сериализовал этот файл cookie и восстановил его позже, теперь этот файл cookie будет отправляться независимо от порта, используемого для целевого URL-адреса (при прочих равных условиях), и это может фактически привести к поломке, если сайт решит, что просмотр такого файла cookie в другом месте был вопрос.

1 голос
/ 10 июля 2019

Наконец-то найдено решение, нужно указать домен

from requests import Session

with Session() as sess:
    #sess.cookies.update({"sessioncookie": "1234567890"})
    sess.cookies.set('sessioncookie','1234567890', domain='httpbin.org')
    sess.get("https://httpbin.org/cookies/set/sessioncookie/0987654321")
    print(sess.cookies.items())
    # Only one cookie
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...