Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression in Python 3.2 cookie parsing #66947

Closed
timgraham mannequin opened this issue Oct 29, 2014 · 22 comments
Closed

Regression in Python 3.2 cookie parsing #66947

timgraham mannequin opened this issue Oct 29, 2014 · 22 comments
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@timgraham
Copy link
Mannequin

timgraham mannequin commented Oct 29, 2014

BPO 22758
Nosy @birkenfeld, @pitrou, @bitdancer, @berkerpeksag, @floppym, @timgraham
Files
  • failing-django-tests-22758.txt
  • cookie-pickling-fix.diff
  • secure-httponly-3.2-backport.diff
  • secure-httponly-3.2-backport.diff
  • secure-httponly-3.2-backport.diff
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2016-07-10.18:03:25.133>
    created_at = <Date 2014-10-29.10:14:37.897>
    labels = ['type-bug', 'library']
    title = 'Regression in Python 3.2 cookie parsing'
    updated_at = <Date 2016-07-14.03:37:23.651>
    user = 'https://github.com/timgraham'

    bugs.python.org fields:

    activity = <Date 2016-07-14.03:37:23.651>
    actor = 'python-dev'
    assignee = 'none'
    closed = True
    closed_date = <Date 2016-07-10.18:03:25.133>
    closer = 'r.david.murray'
    components = ['Library (Lib)']
    creation = <Date 2014-10-29.10:14:37.897>
    creator = 'Tim.Graham'
    dependencies = []
    files = ['37061', '37062', '37127', '38609', '39512']
    hgrepos = []
    issue_num = 22758
    keywords = ['patch']
    message_count = 22.0
    messages = ['230200', '230201', '230202', '230203', '230204', '230205', '230241', '230243', '230363', '230572', '230586', '230619', '230638', '238714', '244141', '256062', '261882', '270109', '270113', '270116', '270119', '270358']
    nosy_count = 8.0
    nosy_names = ['georg.brandl', 'pitrou', 'Arfrever', 'r.david.murray', 'python-dev', 'berker.peksag', 'floppymaster', 'Tim.Graham']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue22758'
    versions = ['Python 3.2']

    @timgraham
    Copy link
    Mannequin Author

    timgraham mannequin commented Oct 29, 2014

    I noticed some failing Django tests on Python 3.2.6 the other day. The regression is caused by this change: 572d9c5

    Behavior before that commit (and on other version of Python even after that commit):

    >>> from http.cookies import SimpleCookie
    >>> SimpleCookie("Set-Cookie: foo=bar; Path=/")
    <SimpleCookie: foo='bar'>

    New broken behavior on Python 3.2.6:

    >>> from http.cookies import SimpleCookie
    >>> SimpleCookie("Set-Cookie: foo=bar; Path=/")
    <SimpleCookie: >

    Python 3.2.6 no longer accepts the "Set-Cookie: " prefix to BaseCookie.load:

    >>> SimpleCookie("Set-Cookie: foo=bar; Path=/")
    <SimpleCookie: >
    >>> SimpleCookie("foo=bar; Path=/")
    <SimpleCookie: foo='bar'>

    This issue doesn't affect 2.7, 3.3, or 3.4 because of b92e104 (this commit wasn't backported to 3.2 because that branch is in security-fix-only mode).

    I asked Berker about this and he suggested to create this issue and said, "If Georg is OK to backout the commit I can write a patch with additional test cases and commit it."

    He also confirmed the regression as follows:

    I've tested your example on Python 2.7.8, 3.2.6, 3.3.6, 3.4.2, 3.5.0 (all unreleased development versions - they will be X.Y.Z+1) and looks like it's a regression.

    My test script is:

    try:
        from http.cookies import SimpleCookie
    except ImportError:
        from Cookie import SimpleCookie
    
        c = SimpleCookie("Set-Cookie: foo=bar; Path=/")
        print(c)

    Here are the results:

    Python 2.7.8:
    Set-Cookie: foo=bar; Path=/

    Python 3.5.0:
    Set-Cookie: foo=bar; Path=/

    Python 3.4.2:
    Set-Cookie: foo=bar; Path=/

    Python 3.3.6:
    Set-Cookie: foo=bar; Path=/
    [45602 refs]

    Python 3.2.6:

    [38937 refs]

    @timgraham timgraham mannequin added stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error labels Oct 29, 2014
    @pitrou
    Copy link
    Member

    pitrou commented Oct 29, 2014

    Is it a normal use of SimpleCookie? The docs don't seem to imply it:

    """
    >>> C = cookies.SimpleCookie()
    >>> C.load("chips=ahoy; vienna=finger") # load from a string (HTTP header)
    """

    In any case, it's up to Georg to decide. But changeset 572d9c5 fixes a security issue reported to security@python.org (the report included a concrete example of how to exploit it under certain conditions).

    @pitrou
    Copy link
    Member

    pitrou commented Oct 29, 2014

    Can you give a pointer to the failing Django test, by the way?

    @timgraham
    Copy link
    Mannequin Author

    timgraham mannequin commented Oct 29, 2014

    I wasn't sure if it was expected behavior or not. I'm attaching a file with the list of failing tests on Django's master.

    Perhaps more useful is a reference to the problematic usage in Django:

    https://github.com/django/django/blob/349471eeb9a4db2f5d8e95cb6555e7b3f2c94e3f/django/http/response.py#L208-L217

    That logic was added to fix https://code.djangoproject.com/ticket/15863.

    @pitrou
    Copy link
    Member

    pitrou commented Oct 29, 2014

    Ah, so it's about round-tripping between SimpleCookie.__str__() and SimpleCookie.__init__(). That sounds like a reasonable behaviour to preserve (and easier than parsing arbitrary Set-Cookie headers). IMO we should also add for tests for it in other versions.

    @birkenfeld
    Copy link
    Member

    OK, so there are two root issues here:

    • Django uses __init__(str()) roundtripping, which is not explicitly supported by the library, and worked by accident with previous versions. That it works again with 3.3+ is another accident, and a bug.

    (The change for bpo-16611 reintroduces "lax" parsing behavior that the security fix was supposed to prevent.)

    • BaseCookie doesn't roundtrip correctly when pickled with protocol >= 2. This should be fixed in upcoming bugfix releases.

    I would advise Django to subclass SimpleCookie and fix the pickling issue, which is not hard (see attached diff).

    @timgraham
    Copy link
    Mannequin Author

    timgraham mannequin commented Oct 29, 2014

    Thank-you Georg; I believe I was able to fix some of the failures by patching Django as you suggested.

    However, I think I found another issue due to bpo-16611 (support for httponly/secure cookies) not being backported to Python 3.2. The issue is that any cookies that appear after one that uses httponly or secure are dropped:

    >>> from http.cookies import SimpleCookie
    >>> c = SimpleCookie()
    >>> c['a'] = 'b'
    >>> c['a']['httponly'] = True
    >>> c['d'] = 'e'
    >>> out = c.output(header='', sep='; ')
    >>> SimpleCookie(out)
    <SimpleCookie: a='b'>

    Here's another example using the 'domain' option to show the same flow from above working as expected:

    >>> c = SimpleCookie()
    >>> c['a'] = 'b'
    >>> c['a']['domain'] = 'foo.com'
    >>> c['d'] = 'e'
    >>> out = c.output(header='', sep='; ')
    >>> SimpleCookie(out)
    <SimpleCookie: a='b' d='e'>

    It seems to me this may warrant backporting httponly/secure support to Python 3.2 now that cookie parsing is more strict (unless Django is again relying on incorrect behavior).

    @birkenfeld
    Copy link
    Member

    Thanks, this is indeed a regression.

    @timgraham
    Copy link
    Mannequin Author

    timgraham mannequin commented Oct 31, 2014

    FYI, I created bpo-22775 and submitted a patch for the issue that SimpleCookie doesn't pickle properly with HIGHEST_PROTOCOL.

    @timgraham
    Copy link
    Mannequin Author

    timgraham mannequin commented Nov 4, 2014

    Georg, how do want to proceed with this issue? Should we backport bpo-16611 (support for parsing secure/httponly flag) to 3.2 to fix this regression and then create a separate issue to fix the lax parsing issue on all versions?

    @birkenfeld
    Copy link
    Member

    That seems like the best course of action.

    @timgraham
    Copy link
    Mannequin Author

    timgraham mannequin commented Nov 4, 2014

    The patch from bpo-16611 applies cleanly to 3.2. I added a mention in Misc/NEWS and confirmed that all tests pass.

    @timgraham
    Copy link
    Mannequin Author

    timgraham mannequin commented Nov 4, 2014

    I also created bpo-22796 for the lax parsing issue.

    @timgraham
    Copy link
    Mannequin Author

    timgraham mannequin commented Mar 20, 2015

    Patch updated to fix conflict in NEWS. Could we have it committed to ensure it gets fixed in the next 3.2 released?

    @timgraham
    Copy link
    Mannequin Author

    timgraham mannequin commented May 27, 2015

    Patch rebased again after cookie fix from bpo-22931.

    @timgraham
    Copy link
    Mannequin Author

    timgraham mannequin commented Dec 7, 2015

    Given the inactivity here, I guess the patch won't be applied before Python 3.2 is end-of-life so I'm going to close the ticket.

    @timgraham timgraham mannequin closed this as completed Dec 7, 2015
    @berkerpeksag
    Copy link
    Member

    I will commit this to the 3.2 branch today.

    @berkerpeksag berkerpeksag reopened this Mar 17, 2016
    @bitdancer
    Copy link
    Member

    My understanding is that there is a commit hook that prevents pushing to the 3.2 branch, so that Georg needs to do this. I've applied the patch and run the tests myself, and agree that it passes (as in, none of the test failures I see are related to cookies). This isn't set to release blocker...should it be (ie: since this is the last release do we want to make sure it gets in)?

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Jul 10, 2016

    New changeset d22fadc18d01 by R David Murray in branch '3.2':
    bpo-22758: fix regression in handling of secure cookies.
    https://hg.python.org/cpython/rev/d22fadc18d01

    @bitdancer
    Copy link
    Member

    Oops. I guess there's no commit hook after all.

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Jul 10, 2016

    New changeset 1c07bd735282 by R David Murray in branch '3.3':
    bpo-22758 null merge
    https://hg.python.org/cpython/rev/1c07bd735282

    New changeset 5b712993dce5 by R David Murray in branch '3.4':
    bpo-22758 null merge
    https://hg.python.org/cpython/rev/5b712993dce5

    New changeset 26342c9e8c1d by R David Murray in branch '3.5':
    bpo-22758 null merge
    https://hg.python.org/cpython/rev/26342c9e8c1d

    New changeset ce140ed0a56c by R David Murray in branch 'default':
    bpo-22758 null merge
    https://hg.python.org/cpython/rev/ce140ed0a56c

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Jul 14, 2016

    New changeset a0bf31e50da5 by Martin Panter in branch '3.2':
    Issue bpo-22758: Move NEWS entry to Library section
    https://hg.python.org/cpython/rev/a0bf31e50da5

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    4 participants