Anti tamper: avoid submitting any suffix

This commit is contained in:
Son NK 2020-05-02 12:15:03 +02:00
parent 5e174b08f4
commit db92003e5f
4 changed files with 32 additions and 16 deletions

View file

@ -123,6 +123,7 @@ DB_URI = os.environ["DB_URI"]
# Flask secret
FLASK_SECRET = os.environ["FLASK_SECRET"]
MAILBOX_SECRET = FLASK_SECRET + "mailbox"
CUSTOM_ALIAS_SECRET = FLASK_SECRET + "custom_alias"
# AWS
AWS_REGION = "eu-west-3"

View file

@ -42,7 +42,7 @@
<div class="col-sm-6 p-1">
<select class="form-control" name="suffix">
{% for suffix in suffixes %}
<option value="{{ suffix[1] }}">
<option value="{{ suffix[2] }}">
{% if suffix[0] %}
{{ suffix[1] }} (your domain)
{% else %}

View file

@ -1,7 +1,12 @@
from flask import render_template, redirect, url_for, flash, request
from flask_login import login_required, current_user
from itsdangerous import TimestampSigner, SignatureExpired
from app.config import DISABLE_ALIAS_SUFFIX, ALIAS_DOMAINS
from app.config import (
DISABLE_ALIAS_SUFFIX,
ALIAS_DOMAINS,
CUSTOM_ALIAS_SECRET,
)
from app.dashboard.base import dashboard_bp
from app.email_utils import email_belongs_to_alias_domains, get_email_domain_part
from app.extensions import db
@ -9,6 +14,8 @@ from app.log import LOG
from app.models import Alias, CustomDomain, DeletedAlias, Mailbox
from app.utils import convert_to_id, random_word, word_exist
signer = TimestampSigner(CUSTOM_ALIAS_SECRET)
@dashboard_bp.route("/custom_alias", methods=["GET", "POST"])
@login_required
@ -24,27 +31,24 @@ def custom_alias():
return redirect(url_for("dashboard.index"))
user_custom_domains = [cd.domain for cd in current_user.verified_custom_domains()]
# List of (is_custom_domain, alias-suffix)
# List of (is_custom_domain, alias-suffix, time-signed alias-suffix)
suffixes = []
# put custom domain first
for alias_domain in user_custom_domains:
suffixes.append((True, "@" + alias_domain))
suffix = "@" + alias_domain
suffixes.append((True, suffix, signer.sign(suffix).decode()))
# then default domain
for domain in ALIAS_DOMAINS:
suffixes.append(
(
False,
("" if DISABLE_ALIAS_SUFFIX else "." + random_word()) + "@" + domain,
)
)
suffix = ("" if DISABLE_ALIAS_SUFFIX else "." + random_word()) + "@" + domain
suffixes.append((False, suffix, signer.sign(suffix).decode()))
mailboxes = [mb.email for mb in current_user.mailboxes()]
if request.method == "POST":
alias_prefix = request.form.get("prefix")
alias_suffix = request.form.get("suffix")
signed_suffix = request.form.get("suffix")
mailbox_email = request.form.get("mailbox")
alias_note = request.form.get("note")
@ -55,6 +59,18 @@ def custom_alias():
flash("Something went wrong, please retry", "warning")
return redirect(url_for("dashboard.custom_alias"))
# hypothesis: user will click on the button in the 300 secs
try:
alias_suffix = signer.unsign(signed_suffix, max_age=300).decode()
except SignatureExpired:
LOG.error("Alias creation time expired")
flash("Alias creation time is expired, please retry", "warning")
return redirect(url_for("dashboard.custom_alias"))
except Exception:
LOG.error("Alias suffix is tampered, user %s", current_user)
flash("Unknown error, refresh the page", "error")
return redirect(url_for("dashboard.custom_alias"))
if verify_prefix_suffix(
current_user, alias_prefix, alias_suffix, user_custom_domains
):

View file

@ -1,6 +1,7 @@
from flask import url_for
from app.config import EMAIL_DOMAIN
from app.dashboard.views.custom_alias import signer
from app.extensions import db
from app.models import Mailbox
from app.utils import random_word
@ -12,14 +13,12 @@ def test_add_alias_success(flask_client):
db.session.commit()
word = random_word()
suffix = f".{word}@{EMAIL_DOMAIN}"
suffix = signer.sign(suffix).decode()
r = flask_client.post(
url_for("dashboard.custom_alias"),
data={
"prefix": "prefix",
"suffix": f".{word}@{EMAIL_DOMAIN}",
"mailbox": user.email,
},
data={"prefix": "prefix", "suffix": suffix, "mailbox": user.email,},
follow_redirects=True,
)