mirror of
https://github.com/simple-login/app.git
synced 2024-09-30 05:31:30 +02:00
commit
54b32be321
@ -559,6 +559,7 @@ Below are pointers to different topics:
|
|||||||
- [UFW - uncomplicated firewall](docs/ufw.md)
|
- [UFW - uncomplicated firewall](docs/ufw.md)
|
||||||
- [SES - Amazon Simple Email Service](docs/ses.md)
|
- [SES - Amazon Simple Email Service](docs/ses.md)
|
||||||
- [Upgrade existing SimpleLogin installation](docs/upgrade.md)
|
- [Upgrade existing SimpleLogin installation](docs/upgrade.md)
|
||||||
|
- [Enforce SPF](docs/enforce-spf.md)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
@ -64,7 +64,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- END Change email -->
|
<!-- END Change email -->
|
||||||
|
|
||||||
|
|
||||||
{% if spf_available %}
|
{% if spf_available %}
|
||||||
|
<!--
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="form-name" value="force-spf">
|
<input type="hidden" name="form-name" value="force-spf">
|
||||||
@ -92,6 +94,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
Profile
|
Profile
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
These informations will be filled up automatically when you use "Sign in with SimpleLogin" button
|
This information will be filled in automatically when you use "Sign in with SimpleLogin" button.
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group mt-3">
|
<div class="form-group mt-3">
|
||||||
<label class="form-label">Name</label>
|
<label class="form-label">Name</label>
|
||||||
|
51
docs/enforce-spf.md
Normal file
51
docs/enforce-spf.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
Some email services like Gmail, Protonmail, etc don't have a strict SPF record (`-all`) to support the "classic" email forwarding
|
||||||
|
that is usually used for group mailing list. In this scenario, an email is sent to a group is forwarded as-is,
|
||||||
|
breaking therefore the SPF.
|
||||||
|
|
||||||
|
A malicious hacker could use this security fail to impersonate your alias via the reverse-alias. This rarely happens
|
||||||
|
as the reverse-alias is generated randomly and is unique for each sender.
|
||||||
|
|
||||||
|
However if you want to prevent this kind of attack, you can enforce the SPF policy even if your mailbox uses a "soft" policy.
|
||||||
|
|
||||||
|
1) Install `postfix-pcre`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt install -y postfix-pcre
|
||||||
|
```
|
||||||
|
|
||||||
|
2) Add `/etc/postfix/body_checks.pcre` file with the following content
|
||||||
|
|
||||||
|
```
|
||||||
|
/^X-SimpleLogin-Client-IP:/ IGNORE
|
||||||
|
```
|
||||||
|
|
||||||
|
3) Add `/etc/postfix/client_headers.pcre` with the following content
|
||||||
|
|
||||||
|
```
|
||||||
|
/^([0-9a-f:.]+)$/ prepend X-SimpleLogin-Client-IP: $1
|
||||||
|
```
|
||||||
|
|
||||||
|
4) Add the following lines to your Postfix config file at `/etc/postfix/main.cf`
|
||||||
|
|
||||||
|
```
|
||||||
|
body_checks = pcre:/etc/postfix/body_checks.pcre
|
||||||
|
smtpd_client_restrictions = pcre:/etc/postfix/client_headers.pcre
|
||||||
|
```
|
||||||
|
|
||||||
|
5) Enable `ENFORCE_SPF` in your SimpleLogin config file
|
||||||
|
|
||||||
|
```
|
||||||
|
ENFORCE_SPF=true
|
||||||
|
```
|
||||||
|
|
||||||
|
6) Restart Postfix
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl restart postfix
|
||||||
|
```
|
||||||
|
|
||||||
|
7) Restart SimpleLogin mail handler
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo docker restart sl-email
|
||||||
|
```
|
@ -91,6 +91,8 @@ from server import create_app
|
|||||||
# can happen when user "Reply All" on some email clients
|
# can happen when user "Reply All" on some email clients
|
||||||
_SELF_FORWARDING_STATUS = "550 SL self-forward"
|
_SELF_FORWARDING_STATUS = "550 SL self-forward"
|
||||||
|
|
||||||
|
_IP_HEADER = "X-SimpleLogin-Client-IP"
|
||||||
|
|
||||||
|
|
||||||
# fix the database connection leak issue
|
# fix the database connection leak issue
|
||||||
# use this method instead of create_app
|
# use this method instead of create_app
|
||||||
@ -367,6 +369,8 @@ def handle_forward(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> (bool, s
|
|||||||
delete_header(msg, "Reply-To")
|
delete_header(msg, "Reply-To")
|
||||||
delete_header(msg, "Sender")
|
delete_header(msg, "Sender")
|
||||||
|
|
||||||
|
delete_header(msg, _IP_HEADER)
|
||||||
|
|
||||||
# change the from header so the sender comes from @SL
|
# change the from header so the sender comes from @SL
|
||||||
# so it can pass DMARC check
|
# so it can pass DMARC check
|
||||||
# replace the email part in from: header
|
# replace the email part in from: header
|
||||||
@ -470,25 +474,31 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> (bool, str
|
|||||||
|
|
||||||
mailb: Mailbox = Mailbox.get_by(email=mailbox_email)
|
mailb: Mailbox = Mailbox.get_by(email=mailbox_email)
|
||||||
if ENFORCE_SPF and mailb.force_spf:
|
if ENFORCE_SPF and mailb.force_spf:
|
||||||
if msg["X-SimpleLogin-Client-IP"]:
|
if msg[_IP_HEADER]:
|
||||||
r = spf.check2(
|
LOG.d("Enforce SPF")
|
||||||
i=msg["X-SimpleLogin-Client-IP"], s=envelope.mail_from.lower(), h=None
|
try:
|
||||||
|
r = spf.check2(i=msg[_IP_HEADER], s=envelope.mail_from.lower(), h=None)
|
||||||
|
except Exception:
|
||||||
|
LOG.error(
|
||||||
|
"SPF error, mailbox %s, ip %s", mailbox_email, msg[_IP_HEADER]
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
# TODO: Handle temperr case (e.g. dns timeout)
|
# TODO: Handle temperr case (e.g. dns timeout)
|
||||||
# only an absolute pass, or no SPF policy at all is 'valid'
|
# only an absolute pass, or no SPF policy at all is 'valid'
|
||||||
if r[0] not in ["pass", "none"]:
|
if r[0] not in ["pass", "none"]:
|
||||||
LOG.d(
|
LOG.error(
|
||||||
"SPF validation failed for %s (reason %s)", mailbox_email, r[0],
|
"SPF fail for mailbox %s, reason %s, failed IP %s",
|
||||||
)
|
|
||||||
return False, "550 SL E11"
|
|
||||||
else:
|
|
||||||
LOG.d(
|
|
||||||
"Could not find X-SimpleLogin-Client-IP header %s -> %s",
|
|
||||||
mailbox_email,
|
mailbox_email,
|
||||||
address,
|
r[0],
|
||||||
|
msg[_IP_HEADER],
|
||||||
|
)
|
||||||
|
return False, "451 SL E11"
|
||||||
|
else:
|
||||||
|
LOG.warning(
|
||||||
|
"Could not find %s header %s -> %s", _IP_HEADER, mailbox_email, address,
|
||||||
)
|
)
|
||||||
|
|
||||||
delete_header(msg, "X-SimpleLogin-Client-IP")
|
delete_header(msg, _IP_HEADER)
|
||||||
|
|
||||||
# only mailbox can send email to the reply-email
|
# only mailbox can send email to the reply-email
|
||||||
if envelope.mail_from.lower() != mailbox_email.lower():
|
if envelope.mail_from.lower() != mailbox_email.lower():
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
"""empty message
|
"""empty message
|
||||||
|
|
||||||
Revision ID: 126c5af661b3
|
Revision ID: bdf76f4b65a2
|
||||||
Revises: 026e7a782ed6
|
Revises: 925b93d92809
|
||||||
Create Date: 2020-05-08 23:01:13.644821
|
Create Date: 2020-05-09 14:38:21.695415
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import sqlalchemy_utils
|
import sqlalchemy_utils
|
||||||
@ -11,8 +11,8 @@ import sqlalchemy as sa
|
|||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = '126c5af661b3'
|
revision = 'bdf76f4b65a2'
|
||||||
down_revision = '026e7a782ed6'
|
down_revision = '925b93d92809'
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
|
|
Loading…
Reference in New Issue
Block a user