4
4
import org .hazlewood .connor .bottema .emailaddress .EmailAddressValidator ;
5
5
import org .simplejavamail .MailException ;
6
6
import org .simplejavamail .converter .internal .mimemessage .MimeMessageHelper ;
7
+ import org .simplejavamail .email .AttachmentResource ;
7
8
import org .simplejavamail .email .Email ;
8
9
import org .simplejavamail .email .Recipient ;
9
10
import org .simplejavamail .mailer .config .ProxyConfig ;
20
21
import javax .mail .Session ;
21
22
import javax .mail .internet .MimeMessage ;
22
23
import java .util .EnumSet ;
24
+ import java .util .Map ;
23
25
import java .util .Properties ;
24
26
25
27
import static java .lang .String .format ;
@@ -341,9 +343,18 @@ public final synchronized void sendMail(final Email email, @SuppressWarnings("Sa
341
343
mailSender .send (email , async );
342
344
}
343
345
}
344
-
346
+
345
347
/**
346
348
* Validates an {@link Email} instance. Validation fails if the subject is missing, content is missing, or no recipients are defined.
349
+ * <p>
350
+ * It also checks for illegal characters that would facilitate injection attacks:
351
+ *
352
+ * <ul>
353
+ * <li>http://www.cakesolutions.net/teamblogs/2008/05/08/email-header-injection-security</li>
354
+ * <li>https://security.stackexchange.com/a/54100/110048</li>
355
+ * <li>https://www.owasp.org/index.php/Testing_for_IMAP/SMTP_Injection_(OTG-INPVAL-011)</li>
356
+ * <li>http://cwe.mitre.org/data/definitions/93.html</li>
357
+ * </ul>
347
358
*
348
359
* @param email The email that needs to be configured correctly.
349
360
* @return Always <code>true</code> (throws a {@link MailException} exception if validation fails).
@@ -353,6 +364,28 @@ public final synchronized void sendMail(final Email email, @SuppressWarnings("Sa
353
364
@ SuppressWarnings ({ "SameReturnValue" , "WeakerAccess" })
354
365
public boolean validate (final Email email )
355
366
throws MailException {
367
+ // check for illegal values
368
+ scanForInjectionAttack (email .getSubject (), "email.subject" );
369
+ for (Map .Entry <String , String > headerEntry : email .getHeaders ().entrySet ()) {
370
+ scanForInjectionAttack (headerEntry .getKey (), "email.header.mapEntryKey" );
371
+ scanForInjectionAttack (headerEntry .getValue (), "email.header." + headerEntry .getKey ());
372
+ }
373
+ for (AttachmentResource attachment : email .getAttachments ()) {
374
+ scanForInjectionAttack (attachment .getName (), "email.attachment.name" );
375
+ }
376
+ for (AttachmentResource embeddedImage : email .getEmbeddedImages ()) {
377
+ scanForInjectionAttack (embeddedImage .getName (), "email.embeddedImage.name" );
378
+ }
379
+ scanForInjectionAttack (email .getFromRecipient ().getName (), "email.fromRecipient.name" );
380
+ scanForInjectionAttack (email .getFromRecipient ().getAddress (), "email.fromRecipient.address" );
381
+ scanForInjectionAttack (email .getReplyToRecipient ().getName (), "email.replyToRecipient.name" );
382
+ scanForInjectionAttack (email .getReplyToRecipient ().getAddress (), "email.replyToRecipient.address" );
383
+ for (Recipient recipient : email .getRecipients ()) {
384
+ scanForInjectionAttack (recipient .getName (), "email.recipient.name" );
385
+ scanForInjectionAttack (recipient .getAddress (), "email.recipient.address" );
386
+ }
387
+
388
+ // check for mandatory values
356
389
if (email .getText () == null && email .getTextHTML () == null ) {
357
390
throw new MailerException (MailerException .MISSING_CONTENT );
358
391
} else if (email .getSubject () == null || email .getSubject ().equals ("" )) {
@@ -377,6 +410,16 @@ public boolean validate(final Email email)
377
410
}
378
411
return true ;
379
412
}
413
+
414
+ /**
415
+ * @param value Value checked for suspicious newline characters "\n", "\r" and "%0A" (as acknowledged by SMTP servers).
416
+ * @param valueLabel The name of the field being checked, used for reporting exceptions.
417
+ */
418
+ private static void scanForInjectionAttack (String value , String valueLabel ) {
419
+ if (value != null && (value .contains ("\n " ) || value .contains ("\r " ) || value .contains ("%0A" ))) {
420
+ throw new MailerException (format (MailerException .INJECTION_SUSPECTED , valueLabel , value ));
421
+ }
422
+ }
380
423
381
424
/**
382
425
* Refer to {@link MimeMessageHelper#signMessageWithDKIM(MimeMessage, Email)}
0 commit comments