Changeset - ae1a499dbd62
[Not reviewed]
0 5 0
Branko Majic (branko) - 2 months ago 2024-02-19 08:56:28
branko@majic.rs
MAR-195: Reject mails with non-matching sender for logged-in users:

- Prevents logged-in user from setting "MAIL FROM" with e-mail address
that does not match either his own account or one of the aliases
that the user receives mails from.
- Reworked the submission port configuration to restrict only based on
sender-related restrictions, merging some of the newer changs from
the workaround.org instructions.
5 files changed with 85 insertions and 12 deletions:
0 comments (0 inline, 0 general)
docs/releasenotes.rst
Show inline comments
 
@@ -68,6 +68,14 @@ Dropped support for Debian 10 (Buster).
 
  * Environment indicator can now be collapsed by clicking on the
 
    arrows on the left side.
 

	
 
* ``mail_server`` role
 

	
 
  * Protection against forging of sender addresses has been
 
    implemented, preventing logged-in users from using arbitrary
 
    sender mail addresses, even if authenticated. Authenticated users
 
    can use either their own login as sender, or one of the aliases
 
    that are associated with their mail account.
 

	
 
* ``web_server`` role
 

	
 
  * Added parameter ``environment_indicator`` which is used on the
docs/rolereference.rst
Show inline comments
 
@@ -1073,6 +1073,9 @@ Deployed services are configured as follows:
 
  below).
 
* Postfix is configured to deliver undeliverable bounces to postmaster. This
 
  helps with detecting misconfigured applications and servers.
 
* Postfix is configured to prevent forging of sender addresses for
 
  logged-in users. Logged-in users can use either their own e-mail as
 
  sender, or one of the aliases associated with their e-mail.
 

	
 
Both Postfix and Dovecot expect a specific directory structure in LDAP when
 
doing look-ups:
roles/mail_server/molecule/default/tests/test_client2.py
Show inline comments
 
@@ -126,11 +126,30 @@ def test_smtp_authentication(host):
 
    anywhere.
 
    """
 

	
 
    send = host.run('swaks -tls --port 587 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-mandatory')
 
    send = host.run('swaks -tls --port 587 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from john.doe@domain1 --to root@client1 --server parameters-mandatory')
 
    assert send.rc == 0
 
    assert "Ok: queued as" in send.stdout
 

	
 
    send = host.run('swaks -tls --port 587 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-optional')
 
    send = host.run('swaks -tls --port 587 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from john.doe@domain1 --to root@client1 --server parameters-optional')
 
    assert send.rc == 0
 
    assert "Ok: queued as" in send.stdout
 

	
 

	
 
def test_smtp_authentication_with_alias_sender(host):
 
    """
 
    Tests if SMTP authentication works via TLS and allows sending mails to
 
    anywhere while using sender alias.
 
    """
 

	
 
    send = host.run('swaks -tls --port 587 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from postmaster@domain1 --to root@client1 --server parameters-mandatory')
 
    assert send.rc == 0
 
    assert "Ok: queued as" in send.stdout
 

	
 
    send = host.run('swaks -tls --port 587 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from postmaster@domain1 --to root@client1 --server parameters-optional')
 
    assert send.rc == 0
 
    assert "Ok: queued as" in send.stdout
 

	
 
@@ -142,11 +161,13 @@ def test_smtp_authentication_requires_tls(host):
 

	
 
    auth_error = 28
 

	
 
    send = host.run('swaks --port 587 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-mandatory')
 
    send = host.run('swaks --port 587 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from john.doe@domain1 --to root@client1 --server parameters-mandatory')
 
    assert send.rc == auth_error
 
    assert "Host did not advertise authentication" in send.stderr
 

	
 
    send = host.run('swaks --port 587 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-optional')
 
    send = host.run('swaks --port 587 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from john.doe@domain1 --to root@client1 --server parameters-optional')
 
    assert send.rc == auth_error
 
    assert "Host did not advertise authentication" in send.stderr
 

	
 
@@ -158,19 +179,23 @@ def test_smtp_authentication_requires_submission_port(host):
 

	
 
    auth_error = 28
 

	
 
    send = host.run('swaks --port 25 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-mandatory')
 
    send = host.run('swaks --port 25 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from john.doe@domain1 --to root@client1 --server parameters-mandatory')
 
    assert send.rc == auth_error
 
    assert "Host did not advertise authentication" in send.stderr
 

	
 
    send = host.run('swaks -tls --port 25 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-mandatory')
 
    send = host.run('swaks -tls --port 25 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from john.doe@domain1 --to root@client1 --server parameters-mandatory')
 
    assert send.rc == auth_error
 
    assert "Host did not advertise authentication" in send.stderr
 

	
 
    send = host.run('swaks --port 25 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-optional')
 
    send = host.run('swaks --port 25 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from john.doe@domain1 --to root@client1 --server parameters-optional')
 
    assert send.rc == auth_error
 
    assert "Host did not advertise authentication" in send.stderr
 

	
 
    send = host.run('swaks -tls --port 25 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-optional')
 
    send = host.run('swaks -tls --port 25 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from john.doe@domain1 --to root@client1 --server parameters-optional')
 
    assert send.rc == auth_error
 
    assert "Host did not advertise authentication" in send.stderr
 

	
 
@@ -289,11 +314,13 @@ def test_port_forwarding(host):
 
    assert "Ok: queued as" in send.stdout
 

	
 
    # Submission port.
 
    send = host.run('swaks -tls --port 26 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-mandatory')
 
    send = host.run('swaks -tls --port 26 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from john.doe@domain1 --to root@client1 --server parameters-mandatory')
 
    assert send.rc == 0
 
    assert "Ok: queued as" in send.stdout
 

	
 
    send = host.run('swaks -tls --port 26 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-optional')
 
    send = host.run('swaks -tls --port 26 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from john.doe@domain1 --to root@client1 --server parameters-optional')
 
    assert send.rc == 0
 
    assert "Ok: queued as" in send.stdout
 

	
 
@@ -318,3 +345,29 @@ def test_dovecot_sieve(host):
 
    command = host.run('echo janepassword | sieve-connect --list -s parameters-optional -p 4190 -u jane.doe@domain1 --password 0 || /bin/false')
 
    assert command.rc != 0
 
    assert "Authentication refused by server" in command.stderr
 

	
 

	
 
def test_smtp_sender_forging(host):
 
    """
 
    Tests if SMTP sender forging is possible.
 
    """
 

	
 
    send = host.run('swaks -tls --port 587 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from jane.doe@domain2 --to root@client1 --server parameters-mandatory')
 
    assert send.rc == 24
 
    assert "Sender address rejected: not owned by user john.doe@domain1" in send.stdout
 

	
 
    send = host.run('swaks -tls --port 587 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from jane.doe@domain2 --to root@client1 --server parameters-optional')
 
    assert send.rc == 24
 
    assert "Sender address rejected: not owned by user john.doe@domain1" in send.stdout
 

	
 
    send = host.run('swaks -tls --port 587 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from webmaster@domain2 --to root@client1 --server parameters-mandatory')
 
    assert send.rc == 24
 
    assert "Sender address rejected: not owned by user john.doe@domain1" in send.stdout
 

	
 
    send = host.run('swaks -tls --port 587 --auth-user john.doe@domain1 --auth-password johnpassword '
 
                    '--from webmaster@domain2 --to root@client1 --server parameters-optional')
 
    assert send.rc == 24
 
    assert "Sender address rejected: not owned by user john.doe@domain1" in send.stdout
roles/mail_server/templates/main.cf.j2
Show inline comments
 
@@ -73,6 +73,11 @@ smtp_tls_security_level = may
 
smtpd_relay_restrictions = permit_mynetworks
 
  reject_unauth_destination
 

	
 
# Look-up for list of SASL login names that are allowed to send mails
 
# using the passed-in sender address. Allow sending from both original
 
# mailbox name _and_ associated aliases.
 
smtpd_sender_login_maps = ldap:/etc/postfix/ldap-virtual-mailbox-maps.cf, ldap:/etc/postfix/ldap-virtual-alias-maps.cf
 

	
 
# Reject delivery of mails for domains for which the local server is
 
# not responsible, as well as any mails coming from addresses in one
 
# of the configured RBL's.
roles/mail_server/templates/master.cf.j2
Show inline comments
 
@@ -131,8 +131,12 @@ submission inet n       -       y       -       -       smtpd
 
  -o smtpd_tls_security_level=encrypt
 
  -o smtpd_sasl_auth_enable=yes
 
  -o smtpd_tls_auth_only=yes
 
  -o smtpd_recipient_restrictions=
 
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
 
  -o smtpd_reject_unlisted_recipient=no
 
  -o smtpd_client_restrictions=
 
  -o smtpd_helo_restrictions=
 
  -o smtpd_relay_restrictions=
 
  -o smtpd_sender_restrictions=reject_sender_login_mismatch,permit_sasl_authenticated,reject
 
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
 
  -o smtpd_tls_mandatory_protocols={{ mail_server_smtpd_submission_protocols[mail_server_minimum_tls_protocol] | join(',') }}
 
  -o smtpd_tls_mandatory_ciphers=high
 
  -o tls_high_cipherlist={{ mail_server_tls_ciphers }}
0 comments (0 inline, 0 general)