Avoid cross-site logout attacks

Require POST method for /accounts/logout. This has the side effect of
automatically enabling Django's CSRF protection.

(imported from commit 44b1b6ebaadc1c03006e21ae54ac768e31234801)
This commit is contained in:
Reid Barton 2013-03-05 17:45:02 -05:00
parent bc0dbbb566
commit 6bb9ad4e3c
6 changed files with 17 additions and 3 deletions

View File

@ -11,7 +11,7 @@ urlpatterns = patterns('',
# view we're wrapping to continue to function. # view we're wrapping to continue to function.
url(r'^accounts/login/', 'zephyr.views.login_page', {'template_name': 'zephyr/login.html'}), url(r'^accounts/login/', 'zephyr.views.login_page', {'template_name': 'zephyr/login.html'}),
url(r'^accounts/login/', 'django.contrib.auth.views.login', {'template_name': 'zephyr/login.html'}), url(r'^accounts/login/', 'django.contrib.auth.views.login', {'template_name': 'zephyr/login.html'}),
url(r'^accounts/logout/', 'django.contrib.auth.views.logout_then_login'), url(r'^accounts/logout/', 'zephyr.views.logout_then_login'),
url(r'^accounts/password/reset/$', 'django.contrib.auth.views.password_reset', url(r'^accounts/password/reset/$', 'django.contrib.auth.views.password_reset',
{'post_reset_redirect' : '/accounts/password/reset/done/', {'post_reset_redirect' : '/accounts/password/reset/done/',

View File

@ -111,5 +111,6 @@ var people_list = [
{% include "zephyr/keyboard_shortcuts.html" %} {% include "zephyr/keyboard_shortcuts.html" %}
{% include "zephyr/markdown_help.html" %} {% include "zephyr/markdown_help.html" %}
{% include "zephyr/invite_user.html" %} {% include "zephyr/invite_user.html" %}
{% include "zephyr/logout.html" %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,4 @@
<div class="hidden">
<form id="logout_form" action="/accounts/logout/" method="POST">{% csrf_token %}
</form>
</div>

View File

@ -84,7 +84,7 @@
{% endif %} {% endif %}
<li class="divider"></li> <li class="divider"></li>
<li title="Log out"> <li title="Log out">
<a href="/accounts/logout"> <a href="#logout" onclick="logout();">
<i class="icon-off"></i> Log out <i class="icon-off"></i> Log out
</a> </a>
</li> </li>

View File

@ -739,3 +739,7 @@ function fast_forward_pointer() {
} }
}); });
} }
function logout() {
$('#logout_form').submit();
}

View File

@ -8,7 +8,8 @@ from django.template import RequestContext, loader
from django.utils.timezone import now from django.utils.timezone import now
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core import validators from django.core import validators
from django.contrib.auth.views import login as django_login_page from django.contrib.auth.views import login as django_login_page, \
logout_then_login as django_logout_then_login
from django.db.models import Q from django.db.models import Q
from django.core.mail import send_mail from django.core.mail import send_mail
from zephyr.models import Message, UserProfile, Stream, Subscription, \ from zephyr.models import Message, UserProfile, Stream, Subscription, \
@ -343,6 +344,10 @@ def login_page(request, **kwargs):
pass pass
return template_response return template_response
@require_post
def logout_then_login(request, **kwargs):
return django_logout_then_login(request, kwargs)
def accounts_home(request): def accounts_home(request):
if request.method == 'POST': if request.method == 'POST':
form = HomepageForm(request.POST) form = HomepageForm(request.POST)