improve relaing page
This commit is contained in:
parent
e2e10f234b
commit
21a0a1aa8c
4 changed files with 123 additions and 58 deletions
|
|
@ -9,10 +9,10 @@ sidebar:
|
||||||
import { Aside } from "@astrojs/starlight/components";
|
import { Aside } from "@astrojs/starlight/components";
|
||||||
|
|
||||||
Your mail server is almost ready for use. But one puzzle piece is missing. Your users can receive emails but they cannot
|
Your mail server is almost ready for use. But one puzzle piece is missing. Your users can receive emails but they cannot
|
||||||
send them yet. That is easy to configure but it needs some important precautions.
|
send them yet. Actually this is simple to setup. The security implications make it a bit more complex. So this part of
|
||||||
|
the guide is a bit longer.
|
||||||
|
|
||||||
Please note that there is a difference on how **users** send emails versus how **mail servers** send emails. For
|
Let's begin with the difference of how **users** send emails versus how **mail servers** send emails. For comparison:
|
||||||
comparison:
|
|
||||||
|
|
||||||
- A **mail server** fetches the _MX_ record for the destination domain of the recipient’s email address from DNS. That
|
- A **mail server** fetches the _MX_ record for the destination domain of the recipient’s email address from DNS. That
|
||||||
tells it which mail server to talk to. Then it opens an SMTP connection (TCP port 25) and sends the email.
|
tells it which mail server to talk to. Then it opens an SMTP connection (TCP port 25) and sends the email.
|
||||||
|
|
@ -50,7 +50,10 @@ indeed John, your server must reject the email.
|
||||||
Try for yourself:
|
Try for yourself:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
swaks --server localhost:587 --from john@example.org --to list@example.com -tls
|
swaks --server localhost:587 \
|
||||||
|
--from john@example.org \
|
||||||
|
--to list@example.com \
|
||||||
|
-tls
|
||||||
```
|
```
|
||||||
|
|
||||||
Towards the end of the output you will find:
|
Towards the end of the output you will find:
|
||||||
|
|
@ -74,7 +77,12 @@ We are making sure that his authentication happens over an encrypted connection
|
||||||
Try for yourself and provide a valid user name and password:
|
Try for yourself and provide a valid user name and password:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
swaks --server localhost:587 --from john@example.org --to list@example.com -tls --auth-user john@example.org --auth-password summersun
|
swaks --server localhost:587 \
|
||||||
|
--from john@example.org \
|
||||||
|
--to list@example.com \
|
||||||
|
-tls \
|
||||||
|
--auth-user john@example.org \
|
||||||
|
--auth-password summersun
|
||||||
```
|
```
|
||||||
|
|
||||||
Towards the end of the output you will find:
|
Towards the end of the output you will find:
|
||||||
|
|
@ -331,13 +339,13 @@ As a result you will get the exact same string you used above with "AUTH PLAIN".
|
||||||
Please note that there are two different TCP ports on a mail server that speak SMTP:
|
Please note that there are two different TCP ports on a mail server that speak SMTP:
|
||||||
|
|
||||||
| Service name | SMTP | Submission | Submission TLS |
|
| Service name | SMTP | Submission | Submission TLS |
|
||||||
| -------------------- | ------------------------------------ | ------------------------------------------- | --------------------------- |
|
| -------------------- | ------------------------------------ | ---------------------------- | --------------------- |
|
||||||
| TCP Port | 25 | 587 | 465 |
|
| TCP Port | 25 | 587 | 465 |
|
||||||
| Transport encryption | **Off** at first. STARTTLS optional. | **Off**. Then switch to TLS using STARTTLS. | **On** right from the start |
|
| Transport encryption | **Off** at first. STARTTLS optional. | **Off**. STARTTLS mandatory. | TLS all the time |
|
||||||
| Authentication | Optional [^1] | Mandatory | Mandatory |
|
| Authentication | Optional [^1] | Mandatory | Mandatory |
|
||||||
| Meant for | Servers | Humans | Humans |
|
| Meant for | Servers | Humans | Humans |
|
||||||
| Used by | Mail transport agent (MTA) | Mail user agent (MUA) | Mail user agent (MUA) |
|
| Used by | Mail transport agent (MTA) | Mail user agent (MUA) | Mail user agent (MUA) |
|
||||||
| Your home ISP | may block this port | will allows this port | will allow this port |
|
| Your home ISP | may block this port | will allow this port | will allow this port |
|
||||||
|
|
||||||
[^1]:
|
[^1]:
|
||||||
In previous guides I recommended to set `smtpd_sasl_auth_enable=yes` globally in the `main.cf`. That would indeed
|
In previous guides I recommended to set `smtpd_sasl_auth_enable=yes` globally in the `main.cf`. That would indeed
|
||||||
|
|
@ -352,7 +360,20 @@ or 465.
|
||||||
## Configure the submission service
|
## Configure the submission service
|
||||||
|
|
||||||
All Postfix services are declared in the `/etc/postfix/master.cf` file. Most of them are used by Postfix internally,
|
All Postfix services are declared in the `/etc/postfix/master.cf` file. Most of them are used by Postfix internally,
|
||||||
like `pickup`, `cleanup`, `rewrite` or `bounce`. But let's another section anywhere in there:
|
like `pickup`, `cleanup`, `rewrite` or `bounce`. But let's another section anywhere in there. Run these commands:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
postconf -M submission/inet="submission inet n - y - - smtpd"
|
||||||
|
postconf -P "submission/inet/syslog_name=postfix/submission"
|
||||||
|
postconf -P "submission/inet/smtpd_tls_security_level=encrypt"
|
||||||
|
postconf -P "submission/inet/smtpd_sasl_auth_enable=yes"
|
||||||
|
postconf -P "submission/inet/smtpd_recipient_restrictions=permit_sasl_authenticated,reject"
|
||||||
|
postconf -P "submission/inet/smtpd_sender_restrictions=reject_sender_login_mismatch,permit_sasl_authenticated,reject"
|
||||||
|
```
|
||||||
|
|
||||||
|
That looked confusing, right? What it did was define the `submission` service in the `/etc/postfix/master.cf` service
|
||||||
|
for you using the `postconf` command. You could have achieved the same thing by editing that file and adding this
|
||||||
|
section:
|
||||||
|
|
||||||
```
|
```
|
||||||
submission inet n - y - - smtpd
|
submission inet n - y - - smtpd
|
||||||
|
|
@ -364,7 +385,7 @@ submission inet n - y - - smtpd
|
||||||
|
|
||||||
Some notes on that:
|
Some notes on that:
|
||||||
|
|
||||||
- Lines with options (`-o`) need to be indented.
|
- Lines with options (`-o`) need to be indented so that Postfix understands that they belong to the same service.
|
||||||
- The word `submission` refers to the definition of the service in the `/etc/services` file. So it translates to TCP
|
- The word `submission` refers to the definition of the service in the `/etc/services` file. So it translates to TCP
|
||||||
port 587.
|
port 587.
|
||||||
- The `smtpd` at the end tells Postfix that connections should be handled as incoming SMTP connections.
|
- The `smtpd` at the end tells Postfix that connections should be handled as incoming SMTP connections.
|
||||||
|
|
@ -372,7 +393,23 @@ Some notes on that:
|
||||||
- **smtpd_sasl_auth_enable** enables authentication on this port. SASL is short for _Simple Authentication and Security
|
- **smtpd_sasl_auth_enable** enables authentication on this port. SASL is short for _Simple Authentication and Security
|
||||||
Layer_.
|
Layer_.
|
||||||
- **smtpd_recipient_restrictions** define that only authenticated connections are permitted. Without a username and a
|
- **smtpd_recipient_restrictions** define that only authenticated connections are permitted. Without a username and a
|
||||||
password your connection will be rejected.
|
password your connection will be rejected. The **recipient** keyword tells us that this restricts who the recipient
|
||||||
|
can be.
|
||||||
|
- **smtpd_sender_restrictions** deals with the **sender**. I will explain that in the next section.
|
||||||
|
|
||||||
|
While you are at it, create the `submissions` (with an "s" at the end) service as well:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
postconf -M submissions/inet="submissions inet n - y - - smtpd"
|
||||||
|
postconf -P "submissions/inet/syslog_name=postfix/submissions"
|
||||||
|
postconf -P "submissions/inet/smtpd_tls_wrappermode=yes"
|
||||||
|
postconf -P "submissions/inet/smtpd_sasl_auth_enable=yes"
|
||||||
|
postconf -P "submissions/inet/smtpd_recipient_restrictions=permit_sasl_authenticated,reject"
|
||||||
|
postconf -P "submissions/inet/smtpd_sender_restrictions=reject_sender_login_mismatch,permit_sasl_authenticated,reject"
|
||||||
|
```
|
||||||
|
|
||||||
|
The only difference to the `submission` (without the "s" at the end) is the `smtpd_tls_wrappermode` that switches on TLS
|
||||||
|
encryption right from the start of a connection.
|
||||||
|
|
||||||
Restart the Postfix server:
|
Restart the Postfix server:
|
||||||
|
|
||||||
|
|
@ -383,78 +420,107 @@ systemctl restart postfix
|
||||||
Your users can now use the *submission* port to send email. They just use the port 587 in their mail clients instead of
|
Your users can now use the *submission* port to send email. They just use the port 587 in their mail clients instead of
|
||||||
port 25.
|
port 25.
|
||||||
|
|
||||||
Feel free to send a test mail using the submission port and encryption. You will need to install the libnet-ssleay-perl
|
Feel free to send a test mail using the `submission` port and encryption (using STARTTLS):
|
||||||
package first, so that SWAKS can speak TLS:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
swaks --server localhost:587 \
|
swaks --server localhost:587 \
|
||||||
--from john@example.org \
|
--from john@example.org \
|
||||||
--to lisa@example.com \
|
--to lisa@example.com \
|
||||||
--port 587 -tls \
|
-tls \
|
||||||
--auth-user john@example.org \
|
--auth-user john@example.org \
|
||||||
--auth-password summersun
|
--auth-password summersun
|
||||||
```
|
```
|
||||||
|
|
||||||
<Aside type="caution">
|
Also give the `submissions` service a try:
|
||||||
|
|
||||||
At this point there is still a security flaw. We told Postfix to relay emails only if we authenticate with a valid
|
```
|
||||||
username and password. But will it keep us from impersonating an arbitrary sender address?
|
swaks --server localhost:465 \
|
||||||
|
--from john@example.org \
|
||||||
|
--to lisa@example.com \
|
||||||
|
--tls-on-connect \
|
||||||
|
--auth-user john@example.org \
|
||||||
|
--auth-password summersun
|
||||||
|
```
|
||||||
|
|
||||||
No, it will not restrict that. We could be authenticating as `john@example.org` but send an email in the name of
|
Did you notice the difference? This time we used port **465** and instead of the `-tls` option (which uses STARTTLS to
|
||||||
`brunhilde@example.org`.
|
switch to encryption) we use `--tls-on-connect` that uses TLS right from from the start.
|
||||||
|
|
||||||
If you want to allow users to send as one of their aliases you could create a new \*.cf file with a mapping query like
|
TODO: try sending from roundcube
|
||||||
this: `SELECT email FROM virtual_users WHERE email='%s' UNION SELECT destination FROM virtual_aliases WHERE source='%s'`
|
|
||||||
|
|
||||||
</Aside>
|
|
||||||
|
|
||||||
## Protecting against forged sender addresses
|
## Protecting against forged sender addresses
|
||||||
|
|
||||||
A "forged" sender address means that someone claims to be someone else. Let’s say that John has authenticated and the
|
At this stage, a security issue remains. While Postfix is configured to relay emails only after a successful login with
|
||||||
mail server trusts him. Nothing keeps John from impersonating someone else and sending email in his name? Most email
|
a valid username and password, it does not prevent an authenticated user from impersonating another sender. For example,
|
||||||
service providers have restrictions that you can only send emails if the sender matches your actual email address. Let’s
|
someone could log in as `john@example.org` but send an email appearing to come from `brunhilde@example.net`.
|
||||||
do that, too.
|
|
||||||
|
|
||||||
Postfix provides a setting called
|
You want to see that this work? Let's pretend to be _brunhilde_ while authenticating as _john_:
|
||||||
[smtpd_sender_login_maps](http://www.postfix.org/postconf.5.html#smtpd_sender_login_maps) for that purpose. From the
|
|
||||||
"maps" part you can deduce that it expects a _mapping_ again. This time the two columns mean…
|
|
||||||
|
|
||||||
- Left column: who you claim to be (email’s sender address)
|
```sh
|
||||||
- Right column: who you logged in as (user name after authentiation)
|
swaks --server localhost:587 \
|
||||||
|
--from brunhilde@example.org \
|
||||||
As we use the email address also as a user name we simply need a mapping where the email address is listed on both
|
--to list@example.com \
|
||||||
sides. Fortunately we already have a mapping like that: our _email2email_ mapping that we used earlier as a workaround
|
-tls \
|
||||||
for catchall forwardings. Let’s reuse it. Please run…
|
|
||||||
|
|
||||||
```
|
|
||||||
postconf smtpd_sender_login_maps=mysql:/etc/postfix/mysql-email2email.cf
|
|
||||||
```
|
|
||||||
|
|
||||||
This sets the parameter both for the SMTP port (25) and the submission port (587). Defining these maps is not enough
|
|
||||||
though. You also need to make Postfix act on this. Edit the /etc/postfix/master.cf again and in the _submission_ section
|
|
||||||
add the following option. Make sure the line is indented like all other options:
|
|
||||||
|
|
||||||
```
|
|
||||||
-o smtpd_sender_restrictions=reject_sender_login_mismatch,permit_sasl_authenticated,reject
|
|
||||||
```
|
|
||||||
|
|
||||||
Restart Postfix after this change:
|
|
||||||
|
|
||||||
```
|
|
||||||
systemctl restart postfix
|
|
||||||
```
|
|
||||||
|
|
||||||
You can now try to send email as a different user than you are logged in. Let’s us swaks again to send a spoofed email:
|
|
||||||
|
|
||||||
```
|
|
||||||
swaks --server localhost --from john@example.com \
|
|
||||||
--to john@example.org --port 587 -tls \
|
|
||||||
--auth-user john@example.org \
|
--auth-user john@example.org \
|
||||||
--auth-password summersun
|
--auth-password summersun
|
||||||
```
|
```
|
||||||
|
|
||||||
Please note that John’s actual email address is **not** john@example.**com** but john@example.**org**. So it must be
|
That should not be allowed. But Postfix does not know better and responds with:
|
||||||
rejected. The server should tell you:
|
|
||||||
|
```
|
||||||
|
<~ 250 2.0.0 Ok: queued as EEEB420F51
|
||||||
|
```
|
||||||
|
|
||||||
|
We should fix that. For that purpose Postfix provides a setting called
|
||||||
|
[smtpd_sender_login_maps](http://www.postfix.org/postconf.5.html#smtpd_sender_login_maps). From the "maps" part you can
|
||||||
|
deduce that it expects a _mapping_ again:
|
||||||
|
|
||||||
|
- _Question_: who you **claim** to be (email’s sender address)
|
||||||
|
- _Answer_: who you **logged in as** (user name after authentiation)
|
||||||
|
|
||||||
|
If you think of it, the mapping is simple. The _question_ must match the _answer_. If `john@example.org` wants to be the
|
||||||
|
sender, he must also authenticate as `john@example.org`.
|
||||||
|
|
||||||
|
As we use the email address also as a user name we simply need a mapping where the email address is listed on both
|
||||||
|
sides. Let's create it:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cat > /etc/postfix/mariadb-email2email.cf << EOF
|
||||||
|
user = mailserver
|
||||||
|
password = SECOND-PASSWORD-HERE
|
||||||
|
hosts = 127.0.0.1
|
||||||
|
dbname = mailserver
|
||||||
|
query = SELECT email FROM virtual_users WHERE email='%s'
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chown root:postfix /etc/postfix/mariadb-email2email.cf
|
||||||
|
chmod u=rw,g=r,o= /etc/postfix/mariadb-email2email.cf
|
||||||
|
```
|
||||||
|
|
||||||
|
Tell Postfix to use this mapping for our purpose:
|
||||||
|
|
||||||
|
```
|
||||||
|
postconf smtpd_sender_login_maps=mysql:/etc/postfix/mariadb-email2email.cf
|
||||||
|
```
|
||||||
|
|
||||||
|
You have already added `smtpd_sender_restrictions=reject_sender_login_mismatch` earlier in the master.cf for the
|
||||||
|
`submission` and `submissions` services. So you have achieved these three steps to prevent sender impersonation:
|
||||||
|
|
||||||
|
1. Create a mapping that matches an email address to itself.
|
||||||
|
2. Tell Postfix to use that mapping for `smtpd_sender_login_maps` which controls who can be a sender.
|
||||||
|
3. Enforce that restriction for the `submission` and `submissions` services.
|
||||||
|
|
||||||
|
You can now try to send email as a different user than you are logged in. Let’s us swaks again to send a spoofed email:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
swaks --server localhost:587 \
|
||||||
|
--from brunhilde@example.org \
|
||||||
|
--to list@example.com \
|
||||||
|
--tls \
|
||||||
|
--auth-user john@example.org \
|
||||||
|
--auth-password summersun
|
||||||
|
```
|
||||||
|
|
||||||
|
The server should rightfully reject that wrong sender:
|
||||||
|
|
||||||
```
|
```
|
||||||
~> MAIL FROM:john@example.com
|
~> MAIL FROM:john@example.com
|
||||||
|
|
@ -463,8 +529,7 @@ rejected. The server should tell you:
|
||||||
<~ * 553 5.7.1 john@example.com: Sender address rejected: not owned by user john@example.org
|
<~ * 553 5.7.1 john@example.com: Sender address rejected: not owned by user john@example.org
|
||||||
```
|
```
|
||||||
|
|
||||||
Sorry if the mixture of example.org and example.com in my examples makes this guide less readable. But I can’t use any
|
---
|
||||||
real world domains here. Please just note that sometimes it’s ".com" and sometimes ".org".
|
|
||||||
|
|
||||||
Of course you can test your new security feature in the Roundcube web mail interface as well. In Settings/Identities you
|
Of course you can test your new security feature in the Roundcube web mail interface as well. In Settings/Identities you
|
||||||
can create another sender email address as in:
|
can create another sender email address as in:
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Loading…
Add table
Add a link
Reference in a new issue