#37162: Docs ContactForm example demonstrates poor practices
-------------------------------------+-------------------------------------
Reporter: Mike | Owner: Mike Edmunds
Edmunds |
Type: | Status: assigned
Cleanup/optimization |
Component: | Version: 6.0
Documentation |
Severity: Normal | Keywords:
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
The `ContactForm` used as a running example starting in the
[https://docs.djangoproject.com/en/6.1/topics/forms/#more-on-fields More
on fields] forms topic demonstrates poor practices for implementing a
contact form that sends email:
* It uses the contact's email address (`sender`) as the message's
`from_email`. At best, this
[https://stackoverflow.com/questions/54549797/smtpdataerror-553-brelaying-
disallowed-as-abcemail-com-while-using-contact won't work] (the message
will be rejected by the outgoing server or silently ignored as spam at the
receiving end). At worst, it creates vulnerabilities.
* It passes through `subject` and `message` without any indication they
originated in a web contact form. This can allow high-fidelity phishing
attacks against the organization deploying the form (particularly when
combined with an arbitrary sender address).
I realize the example needs to be kept simple, but Django's docs probably
shouldn't be illustrating insecure approaches.
I'd suggest changing the current:
{{{#!python
from django.core.mail import send_mail
if form.is_valid():
subject = form.cleaned_data["subject"]
message = form.cleaned_data["message"]
sender = form.cleaned_data["sender"]
cc_myself = form.cleaned_data["cc_myself"]
recipients = ["[email protected]"]
if cc_myself:
recipients.append(sender)
send_mail(subject, message, sender, recipients)
return HttpResponseRedirect("/thanks/")
}}}
to something like (also renaming the `sender` form field to `email`
throughout the page):
{{{#!python
from django.core.mail import EmailMessage
if form.is_valid():
subject = form.cleaned_data["subject"]
message = form.cleaned_data["message"]
email = form.cleaned_data["email"]
cc_myself = form.cleaned_data["cc_myself"]
# Send the message, directing replies to the contact's email.
EmailMessage(
subject=f"[via contact form] {subject}",
body=f"Contact email: {email}\n\n{message}",
to=["[email protected]"],
cc=[email] if cc_myself else None,
reply_to=[email],
).send()
return HttpResponseRedirect("/thanks/")
}}}
Note that the `cc` handling there (and in the original) is also not ideal.
Maybe we could come up with some other reason to include a boolean field
in the form? ("Urgent"? "No reply necessary"?)
Or if something like that seems too complicated, maybe we should consider
rewriting the page to use something other than a contact form.
[Noticed this while I was working on #34753. I was considering removing
the contact-form-like example from the
[https://docs.djangoproject.com/en/6.1/topics/email/#preventing-header-
injection Email header injection] section and replacing it with a ref to
this actual-contact-form example.]
--
Ticket URL: <https://code.djangoproject.com/ticket/37162>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/django-updates/0107019eb8790733-3fcf30f3-a959-4358-af49-375348bcb94d-000000%40eu-central-1.amazonses.com.