Uwierzytelnianie DKIM – MimeMessage


Uwierzytelnianie DKIM – MimeMessage

DomainKeys Identified Mail (w skrócie DKIM) służy do tego, aby osoba która otrzymuje daną wiadomość e-mail wiedziała jednoznacznie, że jego nadawca to właściciel adresu z którego wychodzi wiadomość. Wysyłając wiadomość e-mail, nadawca umieszcza w nagłówkach zaszyfrowane informacje na temat maila. W Javie należy odpowiednio przygotować wiadomość MimeMessage dołączając informację o uwierzytelnianiu DKIM.

Dodanie zależności utils-mail-dkim oraz javaxmail do pliku pom.xml:

<!-- add dkim support for java mail -->
<dependency>
    <groupId>net.markenwerk</groupId>
    <artifactId>utils-mail-dkim</artifactId>
    <version>1.1.12</version>
</dependency>
<!-- add dkim support for java mail -->

<!-- sending emails -->
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4.7</version>
</dependency>
<!-- sending emails -->

Dokumentacja biblioteki znajduje się na stronie: https://github.com/markenwerk/java-utils-mail-dkim

Przygotowanie wiadomości MimeMessage zawierającej informacje o DKIM:

Address from = new InternetAddress(sender, name + SPACE + surname);
Address to   = new InternetAddress(recipient);

MimeMessage message = new MimeMessage(session);
message.setFrom(from);

// SpamAssassin missing data header
message.setSentDate(new Date());

message.setRecipient(Message.RecipientType.TO, to);
message.setSubject(subject);

Multipart multipart = new MimeMultipart();

// HTML TEXT
BodyPart messageBodyPartHtml = new MimeBodyPart();
String htmlText              = text + footer;
messageBodyPartHtml.setContent(htmlText, TEXT_HTML + SEMICOLON + UTF_8);
multipart.addBodyPart(messageBodyPartHtml);

// PLAIN TEXT
BodyPart messageBodyPartPlainText = new MimeBodyPart();

messageBodyPartPlainText.setText(html2text(text));
multipart.addBodyPart(messageBodyPartPlainText);

message.setContent(multipart);

UWAGA na:

Address from = new InternetAddress(sender, name + SPACE + surname);

pole from nie może być puste! Inaczej wynik to DKIM fail.

private MimeMessage dkimSignMessage(MimeMessage message, 
                                    String from, 
                                    String signingDomain, 
                                    String selector)  throws Exception {

        DkimSigner dkimSigner = new DkimSigner(
                                               signingDomain,
                                               selector, 
                                               getDkimPrivateKey());

        dkimSigner.setIdentity(from);
        dkimSigner.setHeaderCanonicalization(Canonicalization.SIMPLE);
        dkimSigner.setBodyCanonicalization(Canonicalization.RELAXED);
        dkimSigner.setSigningAlgorithm(SigningAlgorithm.SHA256_WITH_RSA);
        dkimSigner.setLengthParam(true);
        dkimSigner.setZParam(false);
        return new DkimMessage(message, dkimSigner);
}

private InputStream getDkimPrivateKey() {
        final String PRIVATE_KEY_DKIM_LOCATION = "dkim/dkim.der";
        ClassLoader classLoader                = getClass().getClassLoader();
        InputStream is = classLoader.getResourceAsStream(PRIVATE_KEY_DKIM_LOCATION);
        printInputStreamLog(is);
        return is;
}

Wysłanie wiadomości za pomocą klasy javax.mail.Transport:

Transport.send(dkimSignMessage(message, "kontakt@javaleader.pl", "javaleader.pl", DKIM_SELEKTOR));

Niezbędne wpisy DNS dla domeny:

Nazwa hosta: foo._domainkey

gdzie” foo” jest nazwą selektora.

Typ: TXT

Wartość: v=DKIM1;g=*;k=rsa;p=***;s=email;t=s

gdzie *** to wcześniej wygenerowany odpowiednio klucz publiczny zgodnie z instrukcją:

Aby dowiedzieć się czy wpis DNS został poprawnie dodany należy wejść na stronę https://dkimcore.org/tools/keycheck.html.

Wygenerowanie pliku dkim.der:

1. Utworzenie pliku dkim.pem w oparciu o program openssl:

openssl genrsa -out dkim.pem 1024

2. Utworzenie pliku der w oparciu o wygenerowany plik private.pem:

openssl pkcs8 -topk8 -nocrypt -in dkim.pem -outform der -out dkim.der

3. Wygenerowanie klucza publicznego w oparciu o plik private.pem:

format *.pub:

openssl rsa -in private.pem -pubout > key.pub

4. Wyświetlenie klucza publicznego w oparciu o program awk:

awk '/-END PUBLIC KEY-/ { p = 0 }; p; /-BEGIN PUBLIC KEY-/ { p = 1 }' key.pub

Typowe problemy:

brak wpisu DNS lub brak propagacji DNS:

java.io.IOException: net.markenwerk.utils.mail.dkim.DkimException: There is no TXT record available for foo._domainkey.javaleader.pl

klucz prywatny nie pasuje do klucza publicznego:

Incompatible private key for public key

Polecam stronę https://www.mail-tester.com gdzie można sprawdzić poprawność wysyłki swoich maili oraz stronę na której znaleźć można typowe problemy związane z podpisem DKIM – https://blogs.cisco.com/security/common_errors_causing_dkim_verification_failures.


Leave a comment

Your email address will not be published.


*