#34753: Document how to safely construct email addresses
-------------------------------------+-------------------------------------
Reporter: Sylvain Fankhauser | Owner: Mike
Type: | Edmunds
Cleanup/optimization | Status: assigned
Component: Documentation | Version:
Severity: Normal | Resolution:
Keywords: email | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mike Edmunds):
* owner: (none) => Mike Edmunds
* status: new => assigned
Comment:
Copying in some of my notes (from a comment in the earlier PR):
I think we need to substantially rework the whole text in the section, so
it emphasizes the part that's the *developer's* responsibility (preventing
email address syntax injection). I'm not sure how best to word it, but
here's what I'd want to convey and roughly the order:
* Email header injection is a security exploit in which an attacker
manipulates email headers to change the intended sender, recipients, other
headers, or even the entire message.
* Header injection can be caused by newlines in header values (CRLF
injection) or by certain characters like commas and parentheses in address
headers (address syntax injection). [There doesn't seem to be a standard
term for the second type. We could instead say "header content injection"
or "delimiter injection".]
* Django builds on Python's email library, which prevents CRLF injection.
You'll get a `ValueError` if you try to send a message with newlines in
header values.
* But Django can't protect you from address syntax injection. **You are
responsible for properly sanitizing email addresses** constructed from
user-supplied or variable data.
* The best way to construct email addresses is using a well-tested library
function intended for the purpose, like Python's
`email.headerregistry.Address` object or (if you don't need IDN support)
the legacy `email.utils.formataddr()` function. (See example below.)
* **Never** try to use string formatting like `f'"{name}" <{email}>'` to
compose an email address header. This is unsafe, just like building SQL or
HTML with string formatting.
* If you're sending email that includes user-supplied content, you'll
likely need to take steps to prevent spoofing, spear-phishing, spam
cannons, and other malicious uses of email. (Details are beyond the scope
of Django docs.)
* Here's an example contact form that demonstrates some of these concepts…
Also, I've been trying to find a replacement link for
http://www.nyphp.org/phundamentals/8_Preventing-Email-Header-
Injection.html, which is heavily PHP centric and a bit outdated. All the
general descriptions I could find cover only CRLF injection, not address
syntax injection. (And they all use similar PHP code examples.) But maybe
one of these? Most are commercial sites; don't know if we have a policy
about that:
*
https://beaglesecurity.com/blog/vulnerability/email-header-
injection.html
*
https://www.invicti.com/learn/email-injection
*
https://www.acunetix.com/blog/articles/email-header-injection/ (same
content, related company, different formatting)
*
https://en.wikipedia.org/wiki/Email_injection (stub article)
--
Ticket URL: <
https://code.djangoproject.com/ticket/34753#comment:11>