{ "info": { "author": "Philip Mateescu", "author_email": "dev@philipm.at", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Utilities" ], "description": "Permissive CSRF for Django\n==========================\n\nAre you using Django and trying to POST from a normal HTTP page \nto an HTTPS, only to be hit by the puzzling \n*\"Referer checking failed - http://example.com/ does not match https://example.com/\"*?\n\nFirst, you should know that there are `good reasons why this is happening`_,\nand in understanding them you can decide whether trading off security \nfor convenience is worth it.\n\nSecond, the best way to solve this issue is to \nuse HTTPS on all your pages and with packages like `django-sslify`_\nyou have no excuse not to.\n\nIf, after reading all the above, you're still set on making the trade,\nhere is how to use PermissiveCSRF in your Django site.\n\n\nInstallation\n------------\n\nInstall from PyPi::\n \n pip install django-permissivecsrf\n\n.. Or install the version currently in development using pip\n pip install -e git+git://github.com/philipmat/django-permissivecsrf/tarball/master#egg=django-permissivecsrf-dev\n\n\nUsage\n-----\n\nModify your Django ``settings.py`` file and add ``permissivecsrf`` to \nthe list of installed applications::\n\n INSTALLED_APPS = (\n # ...\n 'permissivecsrf',\n )\n\n\n*Prepend* PermissiveCSRF to your ``MIDDLEWARE_CLASSES``::\n\n MIDDLEWARE_CLASSES = (\n 'permissivecsrf.middleware.PermissiveCSRFMiddleware',\n # ...\n )\n\n**Note:** PermissiveCSRF works with `django-sslify`_ too. Although the order doesn't really matter,\nyou probably want PermissiveCSRF after the django-sslify inclusion::\n\n\n MIDDLEWARE_CLASSES = (\n 'sslify.middleware.SSLifyMiddleware',\n 'permissivecsrf.middleware.PermissiveCSRFMiddleware',\n # ...\n )\n\n\nHow does it work?\n-----------------\n\nThe `Django CSRF middleware`_ performs an extra-check if the request is over HTTPS to \nensure that the request came from the same site, i.e. that \nthe referrer (HTTP-Referer header) matches the current site.\n\nIn other words, in ensures that the call to https://example.com/account/login\ncame from another page of https://example.com/. As such, if you put your login \nform on your non-secure homepage, http://example.com/, but use a secure target \nfor your form's *action* attribute, ``
``,\nDjango's check will fail because::\n\n'http://example.com/' != ('https://%s/` % request.get_host())\n\nHowever, Django will not perform the CSRF check at all if the ``request`` object has \nan attribute ``_dont_enforce_csrf_checks`` set to True. That's what PermissiveCSRF relies on:\nif the request came from the same site over HTTP it sets ``_dont_enforce_csrf_checks``\nto True, thus telling the Django CSRF middleware to skip the CSRF check for that request.\n\nThis only happens if:\n\n* ``DEBUG == True``. Your production server should always be HTTPS;\n* The ``HTTP-Referer`` header is present;\n* The request is for an HTTPS URL (i.e. ``request.is_secure() == True``);\n* and the referrer uses HTTP. \n\nIn all other cases it defers to Django for normal processing.\n\n\nTests? Yes!\n-----------\n\n::\n\n $ git clone https://github.com/philipmat/django-permissivecsrf\n $ cd django-permissivecsrf\n $ virtualenv --distribute venv\n $ . venv/bin/activate\n $ python setup.py develop\n ...\n $ python manage.py test permissivecsrf\n ...\n Creating test database for alias 'default'...\n .....\n ----------------------------------------------------------------------\n Ran 5 tests in 0.002s\n\n OK\n Destroying test database for alias 'default'...\n\n\n\nHow to make it even better?\n---------------------------\n\naka *plans for the future*\n\n1. PermissiveCSRF should still perform the CSRF check rather than instruct Django \n to skip it altogether.\n2. Restrict the check for only a set of URLs, e.g. login pages.\n\n\n.. _`good reasons why this is happening`: \n\nWhy is this CSRF HTTP/HTTPS madness happening?\n----------------------------------------------\n\nThe *tl;dr* answer is: to prevent Man-in-the-Middle (MITM) attacks when using HTTPS, because HTTPS headers are encrypted.\n\nThe gist of why this happens is explained in point #4 of the `How it works`_ section of the Django documentation on\nCross Site Request Forgery (emphasis mine):\n\n 4. In addition, for HTTPS requests, strict referer checking is done by CsrfViewMiddleware. \n This is necessary to address a Man-In-The-Middle attack that is possible under HTTPS \n when using a session independent nonce, due to the fact that HTTP 'Set-Cookie' headers \n are (unfortunately) accepted by clients that are talking to a site under HTTPS. \n **(Referer checking is not done for HTTP requests because the presence of the Referer header is not reliable enough under HTTP.)**\n\nIn other words, because the HTTPS headers are encrypted, the *HTTP-Referer* header is resilient \nagainst MITM attacks, so it can be safely used to check and make sure the CSRF cookie or fields\nis originated by the same site that served the page.\n\nThe same check could be made on HTTP calls as well, but since HTTP headers are not encrypted, they \ncould be easily faked and thus the check would be a useless placebo.\n\nThis explanation is also present, in comment form, in this f92a21daa7_ commit by spookylukey aka Luke Plant,\nand further detailed by him in a reply_ to a complaint about the strictness of CSRF Referer check \non the django-developers maillist.\n\nThe take away from all this should be: in production use HTTPS (see `django-sslify`_). Period.\n\n**Seriously, don't use PermissiveCSRF in production. It's a bad idea.** And I should know, I have `plenty of them`_.\n\n\n.. _`django-sslify`: https://github.com/rdegges/django-sslify\n.. _`Django CSRF middleware`: https://github.com/django/django/blob/master/django/middleware/csrf.py\n.. _`Django 13849`: https://code.djangoproject.com/ticket/13849\n.. _reply: https://groups.google.com/d/msg/django-developers/IgWK2vEePtY/R1r3Im4x3UMJ\n.. _f92a21daa7: https://github.com/django/django/commit/f92a21daa7\n.. _`How it works`: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#how-it-works\n.. _`plenty of them`: http://philipm.at/", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/philipmat/django-permissivecsrf", "keywords": "django,CSRF", "license": "BSD", "maintainer": null, "maintainer_email": null, "name": "django-permissivecsrf", "package_url": "https://pypi.org/project/django-permissivecsrf/", "platform": "any", "project_url": "https://pypi.org/project/django-permissivecsrf/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/philipmat/django-permissivecsrf" }, "release_url": "https://pypi.org/project/django-permissivecsrf/1.0.0/", "requires_dist": null, "requires_python": null, "summary": "More permissive CSRF check for Django when moving between HTTP and HTTPS", "version": "1.0.0" }, "last_serial": 790277, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "f3b15fdd0d2b80b91fc15546174c799d", "sha256": "e6671ac198b86354f6a94d1558a41c933456fde5522a06e95cd4e5bec9b5858e" }, "downloads": -1, "filename": "django-permissivecsrf-1.0.0.tar.gz", "has_sig": false, "md5_digest": "f3b15fdd0d2b80b91fc15546174c799d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9150, "upload_time": "2013-01-14T06:09:05", "url": "https://files.pythonhosted.org/packages/ec/8b/41bcc0bec11007585fc68edc32fe0b05cb40425408d5de50d84c38a6ef03/django-permissivecsrf-1.0.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "f3b15fdd0d2b80b91fc15546174c799d", "sha256": "e6671ac198b86354f6a94d1558a41c933456fde5522a06e95cd4e5bec9b5858e" }, "downloads": -1, "filename": "django-permissivecsrf-1.0.0.tar.gz", "has_sig": false, "md5_digest": "f3b15fdd0d2b80b91fc15546174c799d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9150, "upload_time": "2013-01-14T06:09:05", "url": "https://files.pythonhosted.org/packages/ec/8b/41bcc0bec11007585fc68edc32fe0b05cb40425408d5de50d84c38a6ef03/django-permissivecsrf-1.0.0.tar.gz" } ] }