0

The Cookie header that AngularJS is sending looks like:

_ga=redacted; sessionid=redacted; ; csrftoken=redacted

The extra semicolon may not be HTTP compliant.

There are several 'moving' parts to this problem.

  1. Angular $http POST request fails with 403 error and "CSRF Failed: CSRF cookie not set."

  2. The CSRF cookie and header are definitely set in the request as verified in the development tab in Chrome.

  3. Chrome shows COOKIE header text in request as:

    Cookie: _ga=redacted; sessionid=redacted; ; csrftoken=redacted

  4. I have done enough stepping through Django code to see that the raw cookie string, above, comes into the Django app in the HTTP_COOKIE field of the request but the csrftoken cookie never makes it into request.COOKIE. Django's cookie text parser is thrown off by the extra semicolon in the raw cookie text. I don't know if the parser is broken or AngularJS is broken since I don't know the official syntax requirements for raw cookie strings. But the easiest solution would be to figure out how to get Angular to drop that 'blank' cookie.

  5. Django 1.8.2, AngularJS 1.6.7 & Python 2.7.10

  6. This happens in my dev environment on macOS but not on my staging system, which is a Linux box.

UPDATE:

Thanks to help from @xyres I worked around the problem by upgrading to Django 1.8.15. But AngularJS should not send this malformed cookie string, right? How do I fix my AngularJS client?

nmgeek
  • 2,127
  • 1
  • 23
  • 31
  • Multiple cookies are separated by `;`. Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie#Syntax. Anyway, Django's parser parses the cookie string correctly. You can verify that in a shell: `from django.http.cookie import parse_cookie`. Then call `parse_cookie()` and it will parse it correctly. – xyres Dec 09 '17 at 23:16
  • I also wrote a test [similar to this](https://github.com/django/django/blob/1.8.18/tests/handlers/tests.py#L71-L82) to see if the cookies are present in `request.COOKIES`, and it, in fact, has all the cookies after parsing. So, I don't think it's a Django error, but I'll do some more tests to confirm. – xyres Dec 09 '17 at 23:42
  • Okay, I can now confirm that Django's parser correctly parses the cookies and that all the cookies are present in `request.COOKIES`. This time, I tested this with my browser. Here's what I'm thinking why you're seeing this error. Are you sending the `csrfmiddlewaretoken` with you post data or not? Because you have to. Its value should be same as that of the `csrftoken` cookie. See this answer: https://stackoverflow.com/a/20252654/1925257 – xyres Dec 10 '17 at 00:05
  • @xyres, you are on the right track. My Linux system has Django 1.8.5 and my Mac has Django 1.8.2. v1.8.5 of `parse_cookie` works, as you show, but on my Mac `python -c "from django.http.cookie import parse_cookie; print parse_cookie('hello=world;;sec=cook')" ` prints {'hello': 'world'} . It seems Django 1.8.2 `parse_cookie` had a bug that was later fixed. – nmgeek Dec 10 '17 at 00:18
  • Looks like Django has no dependent Python packages. Maybe some change in Python, itself? The Mac has v2.7.10 and the Linux system, v2.7.6. – nmgeek Dec 10 '17 at 00:39
  • Yeah, I also think it's a bug in Python's `Cookie` module. Until v1.8.13 Django used Python's `Cookie.SimpleCookie` for parsing cookies. Can you try this with Python 2 - `import Cookie; c = Cookie.SimpleCookie(); c.load(); print c`? Edit: I also have Python 2.7.6. – xyres Dec 10 '17 at 00:55
  • Yup, it's because in later versions of Python the cookie parser was changed to be more strict. While I can't find the commit where this was changed in Python 2, but for Python 3, I think [this is where](https://github.com/python/cpython/commit/b1e36073cdde71468efa27e88016aa6dd46f3ec7?diff=unified) things changed. Anyway, if you upgrade to Django >= 1.8.15 (not 1.8.13, as I said in previous comment, it was a mistake), you should be fine because Django implements its own cookie parser since this version. – xyres Dec 10 '17 at 01:33
  • @xyres Django v1.8.15 fixed this problem. Do you want to post an answer? I can accept it. – nmgeek Dec 10 '17 at 01:52
  • Ah, it's okay. I don't think this is a reliable solution because if it was changed in Python, it might be changed in Django, as well, in future. So, I think a proper solution would be to make AngularJS send cookies in the correct manner as has been specified in the HTTP specs. But thanks anyway. – xyres Dec 10 '17 at 02:50
  • 2
    I found the bug reports. The bug in Python is still not fixed. The problem was worked around in Django 1.8.15 and some version of 1.9.x. Bug reports: https://code.djangoproject.com/ticket/26158 and https://bugs.python.org/issue25228 – nmgeek Dec 10 '17 at 02:59

0 Answers0