From 3bcdaf62a552f66b90fd604bc2f109dfc2d366fb Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Apr 14 2015 15:34:38 +0000 Subject: Start trying to secure the milter a little With this approach every user notified is receiving a different address to reply to. Then in the milter we check if the address the user replied to correspond to the hash we built and if not drop it. Relates to http://pagure.dev.fedoraproject.org/pagure/issue/98 --- diff --git a/files/pagure.cfg.sample b/files/pagure.cfg.sample index bde6b0d..0ee815f 100644 --- a/files/pagure.cfg.sample +++ b/files/pagure.cfg.sample @@ -23,8 +23,10 @@ EMAIL_ERROR = 'pingou@pingoured.fr' ### Default SMTP server to use for sending emails SMTP_SERVER = 'localhost' -### Email used to sent emails +### Information used to sent notifications FROM_EMAIL = 'pagure@pagure.io' +DOMAIN_EMAIL_NOTIFICATIONS = 'pagure.io' +SALT_EMAIL = '' ### The URL at which the project is available. APP_URL = 'https://pagure.io/' diff --git a/milters/comment_email_milter.py b/milters/comment_email_milter.py index 56722a5..b2ca731 100644 --- a/milters/comment_email_milter.py +++ b/milters/comment_email_milter.py @@ -7,6 +7,7 @@ import base64 import email +import hashlib import os import urlparse import StringIO @@ -122,6 +123,16 @@ class PagureMilter(Milter.Base): self.log('To', msg['to']) self.log('From', msg['From']) + # Ensure the user replied to his/her own notification, not that + # they are trying to forge their ID into someone else's + salt = pagure.APP.config.get('SALT_EMAIL') + m = hashlib.sha512('%s%s%s' % (msg_id, salt, msg['From'])) + if m.hexdigest() != msg['to']: + self.log('hash: %s' % m.hexdigest()) + self.log('to: %s' % msg['to']) + self.log('Hash does not correspond to the destination') + return Milter.CONTINUE + if msg['From'] and msg['From'] == pagure.APP.config.get('FROM_EMAIL'): self.log("Let's not process the email we send") return Milter.CONTINUE diff --git a/pagure/default_config.py b/pagure/default_config.py index 78d642e..3975ed2 100644 --- a/pagure/default_config.py +++ b/pagure/default_config.py @@ -28,11 +28,11 @@ ADMIN_GROUP = 'sysadmin-main' EMAIL_ERROR = 'pingou@pingoured.fr' # The URL at which the project is available. -APP_URL = 'https://fedorahosted.org/pagure/' +APP_URL = 'https://pagure.org/' # The URL to use to clone the git repositories. -GIT_URL_SSH = 'git@pagure.fedorahosted.org' -GIT_URL_GIT = 'git://pagure.fedorahosted.org' +GIT_URL_SSH = 'git@pagure.org' +GIT_URL_GIT = 'git://pagure.org' # Number of items displayed per page @@ -99,7 +99,9 @@ GL_BINDIR = None SMTP_SERVER = 'localhost' # Email used to sent emails -FROM_EMAIL = 'pagure@fedoraproject.org' +FROM_EMAIL = 'pagure@pagure.org' +DOMAIN_EMAIL_NOTIFICATIONS = 'pagure.org' +SALT_EMAIL = '' # Specify which authentication method to use, defaults to `fas` can be or # `local` diff --git a/pagure/lib/notify.py b/pagure/lib/notify.py index fa184c7..ed170c0 100644 --- a/pagure/lib/notify.py +++ b/pagure/lib/notify.py @@ -10,6 +10,7 @@ pagure notifications. """ import datetime +import hashlib import urlparse import smtplib import time @@ -119,7 +120,6 @@ def send_email(text, subject, to_mail, from_email = pagure.APP.config.get( 'FROM_EMAIL', 'pagure@fedoraproject.org') msg['From'] = from_email - msg['Bcc'] = to_mail.replace(',', ', ') if mail_id: msg['mail-id'] = mail_id @@ -131,15 +131,22 @@ def send_email(text, subject, to_mail, # Send the message via our own SMTP server, but don't include the # envelope header. smtp = smtplib.SMTP(pagure.APP.config['SMTP_SERVER']) - try: - smtp.sendmail( - from_email, - to_mail.split(','), - msg.as_string()) - except smtplib.SMTPException as err: - pagure.LOG.exception(err) - finally: - smtp.quit() + for mailto in to_mail.split(','): + lcl_msg = msg + lcl_msg['To'] = mailto + salt = pagure.APP.config.get('SALT_EMAIL') + m = hashlib.sha512('<%s>%s%s' % (mail_id, salt, mailto)) + lcl_msg['Reply-To'] = 'reply+%s@%s' % ( + m.hexdigest(), pagure.APP.config['DOMAIN_EMAIL_NOTIFICATIONS']) + try: + smtp.sendmail( + from_email, + [mailto], + msg.as_string()) + except smtplib.SMTPException as err: + pagure.LOG.exception(err) + finally: + smtp.quit() return msg