diff options
author | Mark Sapiro <msapiro@value.net> | 2012-02-05 13:19:39 -0800 |
---|---|---|
committer | Mark Sapiro <msapiro@value.net> | 2012-02-05 13:19:39 -0800 |
commit | fdd6141b978cdc0876263d962f996eb88964537b (patch) | |
tree | 6836790556e26d896b791946fc60df5d0f88ab8a /Mailman/Cgi/admin.py | |
parent | 3c1fe7bcb3c10650cd039c800aa1356886586873 (diff) | |
download | mailman2-fdd6141b978cdc0876263d962f996eb88964537b.tar.gz mailman2-fdd6141b978cdc0876263d962f996eb88964537b.tar.xz mailman2-fdd6141b978cdc0876263d962f996eb88964537b.zip |
Added Tokio Kikuchi's Cross-site Request Forgery hardening to the admin UI.
Diffstat (limited to '')
-rw-r--r-- | Mailman/Cgi/admin.py | 32 |
1 files changed, 26 insertions, 6 deletions
diff --git a/Mailman/Cgi/admin.py b/Mailman/Cgi/admin.py index 569aa61c..d881241c 100644 --- a/Mailman/Cgi/admin.py +++ b/Mailman/Cgi/admin.py @@ -1,4 +1,4 @@ -# Copyright (C) 1998-2011 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2012 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -41,6 +41,7 @@ from Mailman.htmlformat import * from Mailman.Cgi import Auth from Mailman.Logging.Syslog import syslog from Mailman.Utils import sha_new +from Mailman.CSRFcheck import csrf_check # Set up i18n _ = i18n._ @@ -55,6 +56,8 @@ except NameError: True = 1 False = 0 +AUTH_CONTEXTS = (mm_cfg.AuthListAdmin, mm_cfg.AuthSiteAdmin) + def main(): @@ -83,6 +86,18 @@ def main(): # If the user is not authenticated, we're done. cgidata = cgi.FieldStorage(keep_blank_values=1) + # CSRF check + safe_params = ['VARHELP', 'adminpw', 'admlogin'] + params = cgidata.keys() + if set(params) - set(safe_params): + csrf_checked = csrf_check(mlist, cgidata.getvalue('csrf_token')) + else: + csrf_checked = True + # if password is present, void cookie to force password authentication. + if cgidata.getvalue('adminpw'): + os.environ['HTTP_COOKIE'] = '' + csrf_checked = True + if not mlist.WebAuthenticate((mm_cfg.AuthListAdmin, mm_cfg.AuthSiteAdmin), cgidata.getvalue('adminpw', '')): @@ -174,8 +189,12 @@ def main(): signal.signal(signal.SIGTERM, sigterm_handler) if cgidata.keys(): - # There are options to change - change_options(mlist, category, subcat, cgidata, doc) + if csrf_checked: + # There are options to change + change_options(mlist, category, subcat, cgidata, doc) + else: + doc.addError( + _('The form lifetime has expired. (request forgery check)')) # Let the list sanity check the changed values mlist.CheckValues() # Additional sanity checks @@ -362,7 +381,7 @@ def option_help(mlist, varhelp): url = '%s/%s/%s' % (mlist.GetScriptURL('admin'), category, subcat) else: url = '%s/%s' % (mlist.GetScriptURL('admin'), category) - form = Form(url) + form = Form(url, mlist=mlist, contexts=AUTH_CONTEXTS) valtab = Table(cellspacing=3, cellpadding=4, width='100%') add_options_table_item(mlist, category, subcat, valtab, item, detailsp=0) form.AddItem(valtab) @@ -408,9 +427,10 @@ def show_results(mlist, doc, category, subcat, cgidata): encoding = 'multipart/form-data' if subcat: form = Form('%s/%s/%s' % (adminurl, category, subcat), - encoding=encoding) + encoding=encoding, mlist=mlist, contexts=AUTH_CONTEXTS) else: - form = Form('%s/%s' % (adminurl, category), encoding=encoding) + form = Form('%s/%s' % (adminurl, category), + encoding=encoding, mlist=mlist, contexts=AUTH_CONTEXTS) # This holds the two columns of links linktable = Table(valign='top', width='100%') linktable.AddRow([Center(Bold(_("Configuration Categories"))), |