Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Net::SMTP

 Net::SMTP

とみたまさひろ

November 28, 2020
Tweet

More Decks by とみたまさひろ

Other Decks in Technology

Transcript

  1. SMTP SMTP Simple Mail Transfer Protocol (1982) → (2001) →

    (2008) メールメッセージ形式は → → ポート番号は 25 (smtp) RFC 821 2821 5321 RFC 822 2822 5322 3
  2. % nc smtp.example.com 25 ← 220 smtp.example.com ESMTP Postfix →

    EHLO client.example.net ← 250-smtp.example.com 250-PIPELINING 250-SIZE 102400000 250-VRFY 250-ETRN 250-STARTTLS 250-AUTH DIGEST-MD5 NTLM CRAM-MD5 PLAIN LOGIN 250-ENHANCEDSTATUSCODES 250-8BITMIME 250-DSN 250 SMTPUTF8 4
  3. → MAIL FROM:<[email protected]> ← 250 2.1.0 Ok → RCPT TO:<[email protected]>

    ← 250 2.1.5 Ok → RCPT TO:<[email protected]> ← 250 2.1.5 Ok → DATA ← 354 End data with <CR><LF>.<CR><LF> → From: [email protected] To: [email protected] Cc: [email protected] Subject: test message body . ← 250 2.0.0 Ok: queued as F074F9FB0E → QUIT ← 221 2.0.0 Bye 5
  4. SMTP認証 SMTP認証 メール送信時に認証が必要な場合 PLAIN はユーザー名とパスワードを Base64 しただけの平文 CRAM-MD5 等を使えば Challenge-Response

    方式の暗号化もできるけど サーバー内に平文のパスワードを保持しておかないといけないのがイマイチ → AUTH PLAIN dXNlcm5hbWUAdXNlcm5hbWUAcGFzc3dvcmQ= ← 235 2.7.0 Authentication successful 12
  5. 通信暗号化(STARTTLS) 通信暗号化(STARTTLS) SMTP 接続後に STARTTLS 命令を発行すると それ以降 TLS での暗号化通信になる (465番ポートは接続時からTLS)

    ← 220 smtp.example.com ESMTP Postfix → EHLO client.example.net ← 250-smtp.example.com 250-STARTTLS ... → STARTTLS ← 220 2.0.0 Ready to start TLS --- ここから TLS 通信 --- → EHLO client.example.net ← 250-smtp.example.com ... → AUTH PLAIN dXNlcm5hbWUAdXNlcm5hbWUAcGFzc3dvcmQ= ← 235 2.7.0 Authentication successful 13
  6. 暗号化通信は手動ではできないので openssl を使う % openssl s_client -connect smtp.example.com:587 -starttls smtp

    ...STARTTLS まで自動でやってくれる... --- ここから TLS 通信 --- → EHLO client.example.net ← 250-smtp.example.com ... 14
  7. TLS証明書の検証 TLS証明書の検証 オレオレ証明書とか期限切れ証明書はエラーにしたい % openssl s_client -connect smtp.example.com:587 -starttls smtp

    -verify_return_error ... Verification error: certificate has expired --- New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated Early data was not sent Verify return code: 10 (certificate has expired) --- % 15
  8. STARTTLS STARTTLS Net::SMTP は start よりも前に enabel_starttls が必要なのがイマイチ smtp =

    Net::SMTP.new('smtp.example.com', 587) smtp.enable_starttls smtp.start('client.example.com', 'username', 'password') do ... end 20
  9. TLS(465番ポート) TLS(465番ポート) enabel_starttls じゃなくて enable_tls enable_starttls と enable_tls 両方指定するとエラー smtp

    = Net::SMTP.new('smtp.example.com', 465) smtp.enable_tls smtp.start('client.example.com', 'username', 'password') do ... end 21
  10. 証明書の検証 証明書の検証 デフォルトでは検証しない かなりダメな感じになってきた… smtp = Net::SMTP.new('smtp.example.com', 587) context =

    OpenSSL::SSL::SSLContext.new context.set_params(verify_mode: OpenSSL::SSL::VERIFY_PEER) smtp.enable_starttls(context) smtp.start('client.example.com', 'username', 'password') do ... end 22
  11. 証明書ホスト名の検証 証明書ホスト名の検証 デフォルトでは証明書の検証をしないのに なぜかホスト名の検証だけはしてる(バグっぽい) Net::SMTP は常に #start() の第1引数の文字列を使うので別のサーバ ー名を使うことはできない smtp

    = Net::SMTP.new('192.168.11.22', 587) context = OpenSSL::SSL::SSLContext.new context.set_params(verify_mode: OpenSSL::SSL::VERIFY_PEER) smtp.enable_starttls(context) smtp.start('client.example.com', 'username', 'password') #=> hostname "192.168.11.22" does not match the server # certificate (OpenSSL::SSL::SSLError) 23
  12. デフォルトで STARTTLS を使用 デフォルトで STARTTLS を使用 非互換! 非互換! サーバーが対応していれば自動的に STARTTLS

    を使用 Net::SMTP.start(hostname, port) { ... } → EHLO client.example.net ← 250-smtp.example.com 250-PIPELINING 250-SIZE 102400000 250-VRFY 250-ETRN 250-STARTTLS 250-AUTH DIGEST-MD5 NTLM CRAM-MD5 PLAIN LOGIN 250-ENHANCEDSTATUSCODES 250-8BITMIME 250-DSN 250 SMTPUTF8 26
  13. net-smtp gem net-smtp gem Ruby 2.7 の人はこれで使える 正当な TLS 証明書を持ってないサーバーへの接続が

    エラーになる可能性あり オレオレ証明書とか % gem install net-smtp 30