Python SMTP sūtīšana: STARTTLS 587. portā vai TLS 465. portā?
STARTTLS 587. portā un netiešais TLS 465. portā abi pārnes Python sūtījumu, bet jūsu relay atbilst tikai viens. Salīdziniet rokasspiedienu un kļūdu režīmus.
Abi savienojuma režīmi pārnes vienu un to pašu ziņojumu uz to pašu relay kontu, un atšķirība ir tajā, kur sākas TLS, nevis tajā, kas tiek sūtīts. Viens atveras atklātā tekstā un tiek paaugstināts kanāla iekšienē; otrs ir šifrēts no pirmā baita. Šī vienīgā atšķirība nosaka, ko pieņems stingra relay politika, ko var novērot starpierīce un kuru kļūdas ziņojumu jūs pavadīsiet pēcpusdienu lasot. Lūk, kā es izvēlos starp tiem, kad lietojumprogramma privātā tīklā nodod ziņojumu iekšējam sūtīšanas servisam.
Kur abi režīmi patiešām atšķiras
Uzdevums abos gadījumos ir vienāds: autentificēties kā apstiprinātam kontam, nosaukt atļautu sūtītāju, uzskaitīt saņēmējus un gaidīt, līdz relay uzņemas atbildību. Mainās darbību secība. 587. ports sākas kā atklāta teksta SMTP sesija, EHLO atbildē paziņo STARTTLS un tiek paaugstināts tikai tad, ja klients to pieprasa. 465. ports sagaida TLS rokasspiedienu pirms jebkuras SMTP komandas izteikšanas.
Sūtīšana un relay ir dažādi darbi, tāpēc portu numuri nav aizvietojami ieradumi. RFC 6409 apraksta ziņojumu sūtīšanu kā atsevišķu servisu, un RFC 8314 aptver netiešā TLS variantu, ko lielākā daļa mūsdienu relay piedāvā 465. portā. Ja jūsu relay dokumentē vienu no diviem, šī dokumentācija ir svarīgāka par jebkuru izvēli, kas iegūta pie iepriekšējā darba devēja.
Ko STARTTLS 587. portā jums dod
Paaugstināšana notiek SMTP sarunas iekšienē, tāpēc relay to var paziņot, un klients var atteikties turpināt bez tā. Python starttls() izmet izņēmumu, kad serveris nepiedāvā šo paplašinājumu, un tas pārvērš pazemināšanas mēģinājumu redzamā kļūmē, nevis klusā atklāta teksta pieteikšanās. Šī uzvedība ir režīma galvenais arguments, un uz to ir vērts paļauties apzināti, nevis nejauši.
Iedarbības logs ir mazs, bet reāls: sākotnējā EHLO apmaiņa ir lasāma, un nekas pirms paaugstināšanas nepārnēsā akreditācijas datus. Privātā ceļā starp lietojumprogrammas apakštīklu un iekšējo relay šis logs parasti ir pieņemams. Ceļā, ko jūs nekontrolējat, tieši tas ir iemesls, kāpēc dažas komandas uzstāj uz otru režīmu.
Pārtveršanas ierīce, kas noņem STARTTLS iespēju, rada neizdevušos sūtījumu, nevis atkāpšanos. Tas ir vēlamais rezultāts, un tas ir arī ātrākais veids, kā atklāt, ka kaut kas ceļā pārraksta SMTP.
Ko maina netiešais TLS 465. portā
Atklāta teksta fāzes vispār nav. Klients veic TLS rokasspiedienu, tiklīdz ligzda atveras, pārbauda sertifikātu pret savu uzticamības krātuvi un tikai pēc tam apmainās ar EHLO, AUTH un ziņojumu. Nekas nevar pazemināt sesiju, jo nav atklāta teksta stāvokļa, no kura pārrunāt, un tas novērš veselu pārtveršanas kļūdu klasi.
Pretī tiek iegūta diagnostika. Relay, kas 465. portā atbild ar atklātu SMTP, vai slodzes balansētājs, kas pabeidz TLS ar nepareizu sertifikāta nosaukumu, neizdodas rokasspiedienā un dod jums SSL kļūdu, nevis pasta kļūdu. Kad tas notiek, problēma ir zem lietojumprogrammas, un nekāda ziņojuma konstruēšana to nelabos.
Viena sūtīšanas funkcija, divi transporti
Kods starp režīmiem gandrīz neatšķiras, tāpēc izvēle jāizdara pēc relay politikas, nevis pēc bibliotēkas ērtības. Vispirms eksportējiet iestatījumus, tad palaidiet vienu skriptu, kas izvēlas transportu pēc konfigurētā porta.
export SMTP_HOST=smtp.relay.internal export SMTP_PORT=587 export SMTP_USER=svc-notify export [email protected] export [email protected] export SMTP_PASSWORD="$(cat /run/secrets/smtp_password)"
import os, smtplib, ssl
from email.message import EmailMessage
ctx = ssl.create_default_context()
msg = EmailMessage()
msg["From"] = os.environ["MAIL_FROM"]
msg["To"] = os.environ["MAIL_TEST_TO"]
msg["Subject"] = "relay submission test"
msg.set_content("One authorized test message from the app.")
host = os.environ["SMTP_HOST"]
port = int(os.environ.get("SMTP_PORT", "587"))
if port == 465:
client = smtplib.SMTP_SSL(host, port, context=ctx, timeout=15)
else:
client = smtplib.SMTP(host, port, timeout=15)
client.ehlo()
client.starttls(context=ctx)
client.ehlo()
with client:
client.login(os.environ["SMTP_USER"], os.environ["SMTP_PASSWORD"])
refused = client.send_message(msg)
print("refused:", refused)
create_default_context() pārbauda ķēdi un resursdatora nosaukumu, tāpēc privāts CA ir jāinstalē uzticamības krātuvē, nevis jāapiet ar nepārbaudītu kontekstu. send_message() atgriež vārdnīcu ar saņēmējiem, kurus relay noraidīja; tukša vārdnīca nozīmē, ka tas pieņēma visus. Piecpadsmit sekunžu taimauts ir sākumpunkts, nevis jūsu tīklam pielāgota vērtība.
Turiet paroli ārpus attēla un ārpus žurnāliem. Noslēpums, kas montēts izpildes laikā un nolasīts vidē, ir labi; vides atspoguļošana žurnāla rindā nav labi, un arī AUTH apmaiņas atkļūdošanas pēdas nav.
Izvēlieties pēc relay politikas un ceļa, nevis pēc ieraduma
Trīs nosacījumi to izšķir. Pirmkārt, ko relay patiešām paziņo: serviss, kas klausās tikai 587. portā ar STARTTLS, nav sasniedzams 465. portā, lai cik ļoti jūs gribētu netiešo TLS. Otrkārt, vai ceļš starp lietojumprogrammu un relay ir pietiekami uzticams, lai pieņemtu lasāmu EHLO apmaiņu. Treškārt, vai kaut kas pa vidu pārraksta vai starpnieko SMTP, jo tas nosaka, vai pazemināšanas risks ir teorētisks vai reāls.
Kad relay piedāvā abus, es ņemu 465. portu servisam, kas darbojas bez uzraudzības, un 587. portu tam, kur cilvēks vēro pirmo izvietošanu, tikai tāpēc, ka kļūdu ziņojumi norāda uz dažādiem slāņiem. Šī izvēle ir mana, un tā nav politika.
Lai ko jūs izvēlētos, pierakstiet portu, uzticamības materiālu un sūtītāja domēnu kopā ar izvietošanu. Pēc tam nosūtiet vienu autorizētu testa ziņojumu un apstipriniet, ka relay to pieņēma, saglabājot sūtīšanas rezultātu un jebkuru vēlāku piegādes atskaiti kā atsevišķus ierakstus. Veiksmīga nodošana relay ir lietojumprogrammas atbildības beigas, nevis pierādījums, ka ziņojums sasniedza iesūtni.