You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

csrf.py 6.1KB

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. from django.conf import settings
  2. from django.http import HttpResponseForbidden
  3. from django.template import Context, Engine, TemplateDoesNotExist, loader
  4. from django.utils.translation import gettext as _
  5. from django.utils.version import get_docs_version
  6. # We include the template inline since we need to be able to reliably display
  7. # this error message, especially for the sake of developers, and there isn't any
  8. # other way of making it available independent of what is in the settings file.
  9. # Only the text appearing with DEBUG=False is translated. Normal translation
  10. # tags cannot be used with this inline templates as makemessages would not be
  11. # able to discover the strings.
  12. CSRF_FAILURE_TEMPLATE = """
  13. <!DOCTYPE html>
  14. <html lang="en">
  15. <head>
  16. <meta http-equiv="content-type" content="text/html; charset=utf-8">
  17. <meta name="robots" content="NONE,NOARCHIVE">
  18. <title>403 Forbidden</title>
  19. <style type="text/css">
  20. html * { padding:0; margin:0; }
  21. body * { padding:10px 20px; }
  22. body * * { padding:0; }
  23. body { font:small sans-serif; background:#eee; color:#000; }
  24. body>div { border-bottom:1px solid #ddd; }
  25. h1 { font-weight:normal; margin-bottom:.4em; }
  26. h1 span { font-size:60%; color:#666; font-weight:normal; }
  27. #info { background:#f6f6f6; }
  28. #info ul { margin: 0.5em 4em; }
  29. #info p, #summary p { padding-top:10px; }
  30. #summary { background: #ffc; }
  31. #explanation { background:#eee; border-bottom: 0px none; }
  32. </style>
  33. </head>
  34. <body>
  35. <div id="summary">
  36. <h1>{{ title }} <span>(403)</span></h1>
  37. <p>{{ main }}</p>
  38. {% if no_referer %}
  39. <p>{{ no_referer1 }}</p>
  40. <p>{{ no_referer2 }}</p>
  41. <p>{{ no_referer3 }}</p>
  42. {% endif %}
  43. {% if no_cookie %}
  44. <p>{{ no_cookie1 }}</p>
  45. <p>{{ no_cookie2 }}</p>
  46. {% endif %}
  47. </div>
  48. {% if DEBUG %}
  49. <div id="info">
  50. <h2>Help</h2>
  51. {% if reason %}
  52. <p>Reason given for failure:</p>
  53. <pre>
  54. {{ reason }}
  55. </pre>
  56. {% endif %}
  57. <p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when
  58. <a
  59. href="https://docs.djangoproject.com/en/{{ docs_version }}/ref/csrf/">Django's
  60. CSRF mechanism</a> has not been used correctly. For POST forms, you need to
  61. ensure:</p>
  62. <ul>
  63. <li>Your browser is accepting cookies.</li>
  64. <li>The view function passes a <code>request</code> to the template's <a
  65. href="https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render"><code>render</code></a>
  66. method.</li>
  67. <li>In the template, there is a <code>{% templatetag openblock %} csrf_token
  68. {% templatetag closeblock %}</code> template tag inside each POST form that
  69. targets an internal URL.</li>
  70. <li>If you are not using <code>CsrfViewMiddleware</code>, then you must use
  71. <code>csrf_protect</code> on any views that use the <code>csrf_token</code>
  72. template tag, as well as those that accept the POST data.</li>
  73. <li>The form has a valid CSRF token. After logging in in another browser
  74. tab or hitting the back button after a login, you may need to reload the
  75. page with the form, because the token is rotated after a login.</li>
  76. </ul>
  77. <p>You're seeing the help section of this page because you have <code>DEBUG =
  78. True</code> in your Django settings file. Change that to <code>False</code>,
  79. and only the initial error message will be displayed. </p>
  80. <p>You can customize this page using the CSRF_FAILURE_VIEW setting.</p>
  81. </div>
  82. {% else %}
  83. <div id="explanation">
  84. <p><small>{{ more }}</small></p>
  85. </div>
  86. {% endif %}
  87. </body>
  88. </html>
  89. """
  90. CSRF_FAILURE_TEMPLATE_NAME = "403_csrf.html"
  91. def csrf_failure(request, reason="", template_name=CSRF_FAILURE_TEMPLATE_NAME):
  92. """
  93. Default view used when request fails CSRF protection
  94. """
  95. from django.middleware.csrf import REASON_NO_REFERER, REASON_NO_CSRF_COOKIE
  96. c = {
  97. 'title': _("Forbidden"),
  98. 'main': _("CSRF verification failed. Request aborted."),
  99. 'reason': reason,
  100. 'no_referer': reason == REASON_NO_REFERER,
  101. 'no_referer1': _(
  102. "You are seeing this message because this HTTPS site requires a "
  103. "'Referer header' to be sent by your Web browser, but none was "
  104. "sent. This header is required for security reasons, to ensure "
  105. "that your browser is not being hijacked by third parties."),
  106. 'no_referer2': _(
  107. "If you have configured your browser to disable 'Referer' headers, "
  108. "please re-enable them, at least for this site, or for HTTPS "
  109. "connections, or for 'same-origin' requests."),
  110. 'no_referer3': _(
  111. "If you are using the <meta name=\"referrer\" "
  112. "content=\"no-referrer\"> tag or including the 'Referrer-Policy: "
  113. "no-referrer' header, please remove them. The CSRF protection "
  114. "requires the 'Referer' header to do strict referer checking. If "
  115. "you're concerned about privacy, use alternatives like "
  116. "<a rel=\"noreferrer\" ...> for links to third-party sites."),
  117. 'no_cookie': reason == REASON_NO_CSRF_COOKIE,
  118. 'no_cookie1': _(
  119. "You are seeing this message because this site requires a CSRF "
  120. "cookie when submitting forms. This cookie is required for "
  121. "security reasons, to ensure that your browser is not being "
  122. "hijacked by third parties."),
  123. 'no_cookie2': _(
  124. "If you have configured your browser to disable cookies, please "
  125. "re-enable them, at least for this site, or for 'same-origin' "
  126. "requests."),
  127. 'DEBUG': settings.DEBUG,
  128. 'docs_version': get_docs_version(),
  129. 'more': _("More information is available with DEBUG=True."),
  130. }
  131. try:
  132. t = loader.get_template(template_name)
  133. except TemplateDoesNotExist:
  134. if template_name == CSRF_FAILURE_TEMPLATE_NAME:
  135. # If the default template doesn't exist, use the string template.
  136. t = Engine().from_string(CSRF_FAILURE_TEMPLATE)
  137. c = Context(c)
  138. else:
  139. # Raise if a developer-specified template doesn't exist.
  140. raise
  141. return HttpResponseForbidden(t.render(c), content_type='text/html')