CSRF mitigation hack: reject logins sent with a session cookie.

Configured user agents and logging in as the same user account are
exempted.
This commit is contained in:
Max Goodman
2013-02-27 15:00:26 -08:00
parent 5b1c2a68fb
commit e22fdad2c4
4 changed files with 21 additions and 1 deletions

View File

@@ -447,9 +447,22 @@ class ApiController(RedditController, OAuth2ResourceController):
responder._send_data(modhash = user.modhash())
responder._send_data(cookie = user.make_cookie())
@validatedForm(user = VThrottledLogin(['user', 'passwd']),
@validatedForm(VLoggedOut(),
user = VThrottledLogin(['user', 'passwd']),
rem = VBoolean('rem'))
def _handle_login(self, form, responder, user, rem):
exempt_ua = (request.user_agent and
any(ua in request.user_agent for ua
in g.config.get('exempt_login_user_agents', ())))
if (errors.LOGGED_IN, None) in c.errors:
if user == c.user or exempt_ua:
# Allow funky clients to re-login as the current user.
c.errors.remove((errors.LOGGED_IN, None))
else:
from r2.lib.base import abort
from r2.lib.errors import reddit_http_error
abort(reddit_http_error(409, errors.LOGGED_IN))
if not (responder.has_errors("vdelay", errors.RATELIMIT) or
responder.has_errors("passwd", errors.WRONG_PASSWORD)):
self._login(responder, user, rem)

View File

@@ -183,6 +183,7 @@ class Globals(object):
'case_sensitive_domains',
'reserved_subdomains',
'TRAFFIC_LOG_HOSTS',
'exempt_login_user_agents',
],
ConfigValue.choice: {

View File

@@ -42,6 +42,7 @@ error_list = dict((
('TOO_MANY_THING_IDS', _('you provided too many ids')),
('NOT_AUTHOR', _("you can't do that")),
('NOT_USER', _("you are not logged in as that user")),
('LOGGED_IN', _("you are already logged in")),
('DELETED_LINK', _('the link you are commenting on has been deleted')),
('DELETED_COMMENT', _('that comment has been deleted')),
('DELETED_THING', _('that element has been deleted')),

View File

@@ -1091,6 +1091,11 @@ class VUname(VRequired):
self.param[0]: "a valid, unused, username",
}
class VLoggedOut(Validator):
def run(self):
if c.user_is_loggedin:
self.set_error(errors.LOGGED_IN)
class VLogin(VRequired):
def __init__(self, item, *a, **kw):
VRequired.__init__(self, item, errors.WRONG_PASSWORD, *a, **kw)