mirror of
https://github.com/simple-login/app.git
synced 2024-09-20 23:16:00 +08:00
commit
54b32be321
|
@ -559,6 +559,7 @@ Below are pointers to different topics:
|
|||
- [UFW - uncomplicated firewall](docs/ufw.md)
|
||||
- [SES - Amazon Simple Email Service](docs/ses.md)
|
||||
- [Upgrade existing SimpleLogin installation](docs/upgrade.md)
|
||||
- [Enforce SPF](docs/enforce-spf.md)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
@ -64,7 +64,9 @@
|
|||
</div>
|
||||
<!-- END Change email -->
|
||||
|
||||
|
||||
{% if spf_available %}
|
||||
<!--
|
||||
<div class="card">
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="force-spf">
|
||||
|
@ -92,6 +94,7 @@
|
|||
</div>
|
||||
</form>
|
||||
</div>
|
||||
-->
|
||||
{% endif %}
|
||||
|
||||
<div class="card">
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
Profile
|
||||
</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 class="form-group mt-3">
|
||||
<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
|
||||
_SELF_FORWARDING_STATUS = "550 SL self-forward"
|
||||
|
||||
_IP_HEADER = "X-SimpleLogin-Client-IP"
|
||||
|
||||
|
||||
# fix the database connection leak issue
|
||||
# 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, "Sender")
|
||||
|
||||
delete_header(msg, _IP_HEADER)
|
||||
|
||||
# change the from header so the sender comes from @SL
|
||||
# so it can pass DMARC check
|
||||
# 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)
|
||||
if ENFORCE_SPF and mailb.force_spf:
|
||||
if msg["X-SimpleLogin-Client-IP"]:
|
||||
r = spf.check2(
|
||||
i=msg["X-SimpleLogin-Client-IP"], s=envelope.mail_from.lower(), h=None
|
||||
)
|
||||
# TODO: Handle temperr case (e.g. dns timeout)
|
||||
# only an absolute pass, or no SPF policy at all is 'valid'
|
||||
if r[0] not in ["pass", "none"]:
|
||||
LOG.d(
|
||||
"SPF validation failed for %s (reason %s)", mailbox_email, r[0],
|
||||
if msg[_IP_HEADER]:
|
||||
LOG.d("Enforce SPF")
|
||||
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]
|
||||
)
|
||||
return False, "550 SL E11"
|
||||
else:
|
||||
# TODO: Handle temperr case (e.g. dns timeout)
|
||||
# only an absolute pass, or no SPF policy at all is 'valid'
|
||||
if r[0] not in ["pass", "none"]:
|
||||
LOG.error(
|
||||
"SPF fail for mailbox %s, reason %s, failed IP %s",
|
||||
mailbox_email,
|
||||
r[0],
|
||||
msg[_IP_HEADER],
|
||||
)
|
||||
return False, "451 SL E11"
|
||||
else:
|
||||
LOG.d(
|
||||
"Could not find X-SimpleLogin-Client-IP header %s -> %s",
|
||||
mailbox_email,
|
||||
address,
|
||||
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
|
||||
if envelope.mail_from.lower() != mailbox_email.lower():
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: 126c5af661b3
|
||||
Revises: 026e7a782ed6
|
||||
Create Date: 2020-05-08 23:01:13.644821
|
||||
Revision ID: bdf76f4b65a2
|
||||
Revises: 925b93d92809
|
||||
Create Date: 2020-05-09 14:38:21.695415
|
||||
|
||||
"""
|
||||
import sqlalchemy_utils
|
||||
|
@ -11,8 +11,8 @@ import sqlalchemy as sa
|
|||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '126c5af661b3'
|
||||
down_revision = '026e7a782ed6'
|
||||
revision = 'bdf76f4b65a2'
|
||||
down_revision = '925b93d92809'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
Loading…
Reference in a new issue