Přeskočit na obsah
Tech-Blog Chatujme.cz Chatujme.cz
Programování

Nette Mail přestal psát do podpisu DKIM délku těla, kvůli které šlo připsat cizí text

Podpis DKIM má příjemci zaručit, že se zpráva cestou nezměnila. Knihovna Nette Mail do něj ale psala nepovinný údaj o délce těla, kvůli kterému podpis pokrýval jen zprávu do určitého bajtu a cokoli za ním zůstalo mimo. Verze 4.2.0 z 27. července 2026 ten údaj vypustila a přidala další věci kolem doručitelnosti.

· aktualizováno 1. 9. 2026 · 195 zhlédnutí

Rub starého složeného dopisu s velkou červenohnědou voskovou pečetí a orámovaným poštovním razítkem
Rub složeného dopisu z Revelu, dnešního Tallinnu, s voskovou pečetí a razítkem z 9. února 1855. Podpis DKIM dělá totéž co pečeť, jen se dá nastavit tak, aby kryl jen část dopisu. Foto: Postal authorities of the Russian Empire (Estonia), Wikimedia Commons (volné dílo)

Odeslat e-mail je jeden řádek kódu, doručit ho je horší. Velcí poskytovatelé schránek přijímají zprávu tím ochotněji, čím líp je podepsaná, a k podpisu se používá DKIM: odesílající server spočítá otisk zprávy, zašifruje ho svým soukromým klíčem a výsledek přilepí do hlavičky. Příjemce si veřejný klíč najde v DNS odesílající domény a ověří, že zpráva opravdu odešla odtud a cestou se nezměnila.

PHP knihovna Nette Mail, jeden z balíčků rodiny Nette, to umí dlouho. Jenže do každého podpisu psala jeden nepovinný údaj, kvůli kterému ta záruka platila jen k určitému bajtu. Verze 4.2.0, kterou má Packagist datovanou 27. července 2026, ho vypustila.

Co ten údaj dělal

Hlavička DKIM-Signature je seznam dvojic klíč a hodnota. Tag bh= nese otisk těla zprávy, h= vyjmenovává podepsané hlavičky a b= je vlastní podpis. Nepovinný tag l= k tomu přidává číslo: kolik prvních bajtů těla ten otisk pokrývá. Do verze 4.1.2 ho knihovna doplňovala pokaždé, přímo v seznamu, ze kterého se hlavička skládá:

'v' => '1',
'a' => 'rsa-sha256',
'q' => 'dns/txt',
'l' => strlen($body),
's' => $this->selector,

Ověřovatel na druhé straně nespočítá otisk z celého těla, ale jen z prvního uvedeného počtu bajtů. Co je za ním, do výpočtu nevstupuje. Kdokoli, kdo zprávu cestou drží v ruce, k ní tedy může připsat vlastní obsah, a podpis dál platí. V nové verzi je ten řádek pryč a jinak zůstal seznam skoro stejný.

Norma před tím varuje od roku 2011

Není to objev. Tag l= vznikl pro konference, které do procházejících zpráv připisují patičku a samy je nepodepisují; bez něj by taková patička podpis rozbila. Norma DKIM ale hned vedle popisu té možnosti věnuje jeho zneužití samostatný oddíl 8.2 s názvem Zneužití omezení délky těla. Popisuje přesně ten útok: prostředník připíše obsah, který slouží jen jemu, a připsaná část může v očích příjemce původní zprávu úplně nahradit. Doporučení normy je stručné a v překladu zní, že odesílatelé mají být při použití té značky mimořádně opatrní a posuzovatelé mohou chtít podpisy s ní rovnou ignorovat.

Praktický dopad závisí na tom, jak zprávu vykreslí poštovní klient. Norma jmenuje záměnu struktury MIME a benevolentní zpracování HTML: k původnímu textu se přilepí druhá část zprávy a klient zobrazí ji. Pro čtenáře je to pořád zpráva s platným podpisem od té správné domény.

Podpis se dá chránit i před druhou hlavičkou

S vypuštěním délky těla přišla druhá věc, která míří na příbuznou slabinu. Táž norma v oddílu 8.15 upozorňuje, že z podepsané hlavičky nelze usuzovat na všechny její výskyty: když je podepsaná jedna hlavička From, nikdo tím neručí za to, že jich zpráva nemá víc. A protože leckterý klient zobrazí tu první, kterou najde, je připsání druhé oblíbený trik podvržených zpráv.

Obranou je takzvaný oversigning. Jméno hlavičky se do seznamu h= uvede vícekrát, než se ve zprávě vyskytuje, čímž podpis pokrývá i její neexistenci. Připsání další kopie pak podpis rozbije. V knihovně je to nový parametr oversignHeaders, do kterého se vyjmenují hlavičky k ochraně; ve výchozím stavu je prázdný, takže si o to musí každý říct sám.

Vedle RSA i Ed25519

Původní norma zná jediný podpisový algoritmus, RSA. Ed25519 k němu přidal až RFC 8463 ze září 2018, a to s odůvodněním, že při srovnatelné míře bezpečnosti má výrazně kratší klíče. To se u DKIM hodí, protože veřejný klíč se zveřejňuje jako záznam v DNS.

Nette Mail nově zvládne obojí a nový parametr k tomu nepotřebuje: typ klíče pozná sám podle jeho tvaru. RSA přichází ve formátu PEM, Ed25519 jako surové bajty v base64. Podepisování pak nejde přes OpenSSL, ale přes rozšíření sodium, a když v PHP chybí, knihovna to řekne rovnou při vytváření podepisovače, ne až u prvního odeslání.

Heslo k SMTP dosluhuje

Zbytek novinek je o tom, co dnes žádají velcí poskytovatelé. Microsoft zveřejnil letos v lednu upravený harmonogram odstavení přihlašování jménem a heslem u odesílání přes Exchange Online: do prosince 2026 se nemění nic, na konci prosince 2026 se u stávajících tenantů vypne ve výchozím stavu, u nově založených nebude po tomto datu dostupné vůbec a datum úplného konce Microsoft oznámí ve druhé polovině roku 2027. Zbývá tedy OAuth.

Knihovna proto umí přihlášení tokenem přes mechanismus XOAUTH2. Protože přístupové tokeny vyprší obvykle po hodině, přebírá setAccessToken() vedle řetězce i uzávěru, která se zavolá při každém připojení:

$mailer->setAccessToken(fn() => $oauth->getFreshToken());

Vydávání a obnovování tokenu zůstává na knihovně, kterou k OAuth používáte. Nette Mail řeší jen tu část, která patří do SMTP.

Odhlášení jedním kliknutím

Poslední kus se týká hromadných zpráv. Gmail v pokynech pro odesílatele žádá, aby marketingové zprávy a zprávy zasílané na základě odběru šly odhlásit jedním kliknutím přímo v poštovním klientovi, pokud odesílatel posílá víc než pět tisíc zpráv denně. Technicky to znamená dvojici hlaviček podle RFC 8058 z ledna 2017: v List-Unsubscribe je odkaz a List-Unsubscribe-Post musí obsahovat přesně řetězec List-Unsubscribe=One-Click. Samotný odkaz nestačí, protože ten v hlavičkách existuje od devadesátých let a poštovní software si ho občas otevře sám od sebe.

V knihovně je to jedno volání, kterému se předá adresa a záložní e-mailová adresa pro klienty, kteří požadavek POST odeslat neumějí. Obě hlavičky navíc přibyly do výchozího seznamu podepisovaných, takže cíl odhlašovacího odkazu nejde cestou vyměnit.

Vedle toho přibyl FileMailer, který nic neodesílá a každou zprávu uloží jako soubor .eml do zadaného adresáře, adresy s diakritikou v doméně se převádějí na punycode a STARTTLS vyjednává výhradně TLS 1.2 a 1.3. Vydání je zpětně kompatibilní, takže na aktualizaci stačí composer update nette/mail. Vypuštěná délka těla je z toho všeho jediná změna, o kterou si nikdo neřekne a která se projeví sama.

Zdroje

Programování

PHP Nette DKIM E-mail Bezpečnost

← zpět na výpis