
Question:
I have a Django view with an email form. It allows the user to type a subject and message, and send that as an email to the site admin. I would like to write a unit test that ensures that this view can catch a <a href="https://docs.djangoproject.com/en/1.4/topics/email/#preventing-header-injection" rel="nofollow">BadHeaderError</a>.
subject = contact_form.cleaned_data['subject']
message = contact_form.cleaned_data['message']
try:
mail_admins(
subject=subject,
message=message,
)
except BadHeaderError:
# I want to test this case.
messages.error(request, "Sorry, the email could not be sent. An invalid header was found.")
else:
messages.success(request, "Your email was sent to the admins.")
How do I trigger a BadHeaderError in a unit test?
I know the canonical example of header injection is having a newline character in the subject. However, I wrote a unit test that fills out this form with a newline character in the subject, and it didn't trigger the invalid header message.
# This didn't trigger the invalid header message. So how do I do it?
response = self.client.post(reverse('contact_us'), dict(
subject="Subject goes here\ncc:spamvictim@example.com",
message="Message goes here",
))
<strong>Edit:</strong>
<a href="https://stackoverflow.com/a/12549859/859858" rel="nofollow">Hassek's suggestion</a> of using Mocker is an avenue of approach I hadn't originally considered, and will work for my purpose here. However, I'm curious as to what actually triggers a BadHeaderError in the mail functions - what kind of special character is needed in the subject, if a newline doesn't do it? Or is there another way to trigger the BadHeaderError? I don't know too much about web security, so I'd like to learn these things.
<strong>Edit 2:</strong>
I was using Django 1.3.0.
Answer1:Use a <a href="http://labix.org/mocker" rel="nofollow">mocker</a> on the mail_admins function to raise the BadHeaderError when called. it would be something like this:
from mocker import Mocker, KWARGS
mocker = Mocker()
raise_error = mocker.replace('COMPLETE_PATH_TO_mail_admins_FUNCTION')
# i.e django.contrib.emails.mail_admins
raise_error(KWARGS)
mocker.raise(BadHeaderException)
haven't test this yet but it should help you out :)
Answer2:This snippet is from Django's own tests; this is how they test that this error is raised
def test_header_injection(self):
email = EmailMessage('Subject\nInjection Test', 'Content', 'from@example.com', ['to@example.com'])
self.assertRaises(BadHeaderError, email.message)