Jak wysłać maila?
Ostatnio pojawił się pewien problem. Ktoś w firmie wymyślił, że będziemy do klientów wysyłać jakieś bardzo ważne dane za pomocą maila. Dane te występują w formie plików PDF i są na tyle wrażliwe, że trzeba je jakoś zabezpieczyć. Idea jak najbardziej słuszna, bo kto by chciał, aby dane o jego wynagrodzeniu czy stanie zdrowia były narażone na przeczytanie przez osoby niepowołane. Oczywiście to tylko przykłady, ale dość dobrze oddają zagrożenia, jakie czyhają na nas w dobie wszechobecnego i nielimitowane dostępu do Internetu (ACTA i jej podobne próby cenzurowania na razie pomijam).
Podstawowym założeniem dla zabezpieczenia poczty jest wykorzystanie ogólnodostępnej i dobrze zdefiniowanej metody szyfrowania oraz podpisywania treści. Konkretnie X.509, czyli infrastruktura klucza publicznego. Zrobiło się ciekawie, bo o ile wygenerowanie odpowiedniego certyfikatu (a właściwie pary klucz prywatny – certyfikat) nie jest specjalnie trudne, to wysłanie odpowiednio zabezpieczonego maila z poziomu konsoli Linuksa jest już pewnym wyzwaniem.
Żeby osiągnąć założony cel i zadowolenie klientów, musimy zrobić kilka rzeczy:
1. Musimy posiadać odpowiedni certyfikat do podpisywania maili. Ponieważ podpisywanie odbywa się za pomocą klucza prywatnego, a potwierdzenia autentyczności można dokonać przy użyciu (ogólnie dostępnego) certyfikatu – musimy takową w jakiś sposób zdobyć.
Można ją kupić w dowolnym centrum, jak np. VeriSign – wtedy będziemy wyglądać bardzo profesjonalnie, a nasz certyfikat będzie automatycznie rozpoznawany przez większość używanych obecnie programów. Jest to jedyna rozsądna opcja, jeżeli chcemy taką funkcjonalność oferować klientom. Jednak do testów wygenerowałem sobie certyfikat podpisany przez moje (światowo niezaufane :-)) centrum. Opisów, jak „zrobić” sobie taką infrastrukturę jest w Sieci całkiem sporo i nie będę tego teraz opisywał.
2. Musimy zebrać certyfikaty użytkowników, do których będziemy wysyłać maile. Szyfrowanie danych odbywa się za pomocą certyfikatu (dostępnego publicznie) i bez niego raczej ciężko nam będzie cokolwiek zrobić. Certyfikaty klientów nie muszą by wygenerowane przez zaufane centrum, a nam zależy wyłącznie na tym, aby klucze prywatne, które są z nimi powiązane, były odpowiednio bezpieczne.
3. Ktoś powinien nam dostarczyć odpowiednie dane, które będziemy wysyłać – w moim przypadku będą to pliki PDF, które wygeneruje SAP lub jakiś inny potwór, którego działania nie rozumiem.
4. Trzeba tego PDFa jakoś zaszyfrować, podpisać i wysłać.
I tu zaczynają się schody… o ile zaszyfrowanie i podpisanie maila jest operacją dość prostą:
cat ./plik.txt | openssl smime -encrypt cert_kogos.pem | openssl smime -sign -signer cert.pem -inkey privkey.pem
to wysłanie tego mailem w taki sposób, żeby było poprawnie wyświetlone w czytniku poczty, nie jest już takie oczywiste.
Próbowałem na różne sposoby, jednak za pomocą „czystej” konsoli nie udało mi się osiągnąć tego, co sobie wymyśliłem. Rozwiązaniem okazało się napisanie prostego skryptu w PERLu, który to wszystko po kolei zrobi:
#!/usr/bin/perl
use MIME::Lite;
use Crypt::SMIME;
$wiadomosc = MIME::Lite->new(
From => 'moj_adres@gmail.com',
To => 'odbiorca@wp.pl',
Subject => 'temat',
Type => 'TEXT',
Data => "Dzien dobry\n\nTRESC\n\n-- \nPozdrawiam,\nKonrad"
);
$wiadomosc->attach(
Type => 'application/pdf',
Path => 'tajne_dane.pdf',
Filename => 'tajne_dane.pdf'
);
{
local $/=undef;
open(MY_PKEY, "certs/moj_klucz.pem") || die "open failed: $!"; $privkey = ;
open(MY_CERT, "certs/moj_cert.pem") || die "open failed: $!"; $cert = ;
open(TO_CERT, "certs/cert_odbiorcy.pem") || die "open failed: $!"; $to_cert = ;
}
$smime = Crypt::SMIME->new();
$smime->setPrivateKey($privkey, $cert);
$smime->setPublicKey($to_cert);
$tmp = $smime->sign($wiadomosc->as_string);
open(MAIL, "|/usr/sbin/sendmail -t");
print MAIL $smime->encrypt($tmp);
close(MAIL);
No dobra, biblioteka MIME::Lite została tutaj użyta dość osobliwie, bo wcale nie do wysyłania maili, ale jest to najprostszy sposób sformatowania maila przed jego zaszyfrowaniem, na który wpadłem. Poza tym, PERLa właściwie nie znam, a ten kod powyżej to „składanka” z przykładów, które znalazłem gdzieś w Sieci.
Teraz muszę się jeszcze zająć tematem podpisywania samych PDFów. No bo skoro ma być tak super profesjonalnie, to dlaczego nie? :-)