#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.

Reply via email to