Ben Cooksley wrote: > >If Mailman were to implement basic CSRF protection for all POST requests >that would also slow the attackers down I suspect (as they would have to >make a GET request first and parse it).
I have implemented a simple version of what I think you requested in your post at <http://mail.python.org/pipermail/mailman-users/2012-October/074287.html>. It is implemented by the attached patch against Mailman 2.1.15. The patch will apply to versions 2.1.12 and later with at most line number changes, For older versions, the hashing function Mailman.Utils.sha_new doesn't exist and will need to be changed in the patch to something else. Note that the patch only enables configuring the token for the listinfo subscribe form. To actually enable placement and checking of the token, one must assign a non-empty string value to SUBSCRIBE_FORM_SECRET in mm_cfg.py. I.e., SUBSCRIBE_FORM_SECRET = 'Some site specific string' The actual token is a hex digest of a sha hash of this string plus the list's internal name plus the IP address of the caller. A more secure token would include something more random such as the time of day, but would be a bit more cumbersome to implement - volunteers are welcome. Let us know if this helps. -- Mark Sapiro <m...@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
--- f:/test-mailman-2.1/Mailman/Defaults.py 2012-10-21 12:25:32.265625000 -0700 +++ f:/test-mailman/Mailman/Defaults.py 2012-11-18 15:35:27.906250000 -0800 @@ -111,6 +111,14 @@ # Form lifetime is set against Cross Site Request Forgery. FORM_LIFETIME = hours(1) +# If the following is set to a non-empty string, this string in combination +# with the list name and the IP address of the requestor is used to create +# a hidden hash as part of the subscribe form on the listinfo page. This +# hash is checked upon form submission and the subscribe fails if it doesn't +# match. I.e. the form posted must be first retrieved from the listinfo +# CGI by the same IP that posts it. +SUBSCRIBE_FORM_SECRET = None + # Command that is used to convert text/html parts into plain text. This # should output results to standard output. %(filename)s will contain the # name of the temporary file that the program should operate on. --- f:/test-mailman-2.1/Mailman/Cgi/listinfo.py 2010-09-05 07:38:30.000000000 -0700 +++ f:/test-mailman/Mailman/Cgi/listinfo.py 2012-11-18 16:17:33.265625000 -0800 @@ -184,6 +184,16 @@ replacements['<mm-confirm-password>'] = mlist.FormatSecureBox('pw-conf') replacements['<mm-subscribe-form-start>'] = mlist.FormatFormStart( 'subscribe') + if mm_cfg.SUBSCRIBE_FORM_SECRET: + replacements['<mm-subscribe-form-start>'] += ( + '<input type="hidden" name="sub_form_token" value="%s">\n' \ + % Utils.sha_new(mm_cfg.SUBSCRIBE_FORM_SECRET + + mlist.internal_name() + + os.environ.get('REMOTE_HOST', + os.environ.get('REMOTE_ADDR', + 'w.x.y.z')) + ).hexdigest() + ) # Roster form substitutions replacements['<mm-roster-form-start>'] = mlist.FormatFormStart('roster') replacements['<mm-roster-option>'] = mlist.FormatRosterOptionForUser(lang) --- f:/test-mailman-2.1/Mailman/Cgi/subscribe.py 2011-05-05 13:36:42.000000000 -0700 +++ f:/test-mailman/Mailman/Cgi/subscribe.py 2012-11-18 16:18:31.140625000 -0800 @@ -120,6 +120,13 @@ remote = os.environ.get('REMOTE_HOST', os.environ.get('REMOTE_ADDR', 'unidentified origin')) + # Are we checking the hidden data? + if mm_cfg.SUBSCRIBE_FORM_SECRET: + token = Utils.sha_new(mm_cfg.SUBSCRIBE_FORM_SECRET + + mlist.internal_name() + + remote).hexdigest() + if token != cgidata.getvalue('sub_form_token', ''): + results.append(_('You must GET the form before submitting it.')) # Was an attempt made to subscribe the list to itself? if email == mlist.GetListEmail(): syslog('mischief', 'Attempt to self subscribe %s: %s', email, remote)
------------------------------------------------------ Mailman-Users mailing list Mailman-Users@python.org http://mail.python.org/mailman/listinfo/mailman-users Mailman FAQ: http://wiki.list.org/x/AgA3 Security Policy: http://wiki.list.org/x/QIA9 Searchable Archives: http://www.mail-archive.com/mailman-users%40python.org/ Unsubscribe: http://mail.python.org/mailman/options/mailman-users/archive%40jab.org