Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
メール認証とRuby
Search
uvb_76
March 07, 2024
Programming
1.2k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
メール認証とRuby
uvb_76
March 07, 2024
More Decks by uvb_76
See All by uvb_76
地元にいないローカルオーガナイザーの立ち回り
uvb_76
2
1.5k
ユーザーにサブドメインの ECサイトを提供したい (あるいは) 2026年函館で一番熱くなるかもしれない言語の話
uvb_76
0
920
Rails 7.2 のリリースノートを見て思ったこと
uvb_76
0
980
Rails Girls ガイドを使って社内で Rails 講座を開催した
uvb_76
0
170
問い合わせ調査との付き合い方
uvb_76
0
260
yawaraka zouzei
uvb_76
0
2.1k
開発環境(物理)を作る
uvb_76
0
1.8k
Other Decks in Programming
See All in Programming
typoなんかねぇよ
raspython3
0
230
Pythonの実行はどこまで賢くなったのか? CPythonとPyPyから見る最適化のしくみ
curekoshimizu
3
1.2k
Dockerfile CMD for Node.js
grazie1999
0
110
不幸な GC
chencmd
0
470
S3 を使うアプリケーションをローカル完結で動かすことに全力を注いでみた / Running S3 Apps Offline
contour_gara
0
570
ここ半年くらいでAIに作らせたR用ツール
eitsupi
0
400
「寝てても仕事が進む」Claude Codeで組む第二の脳
tomoyafujita2016
0
350
夏だ!祭りだ!祭りとはドメインモデリングでは?
ryugen04
0
350
テーブルをDELETEした
yuzneri
0
150
What's New in Android 2026
veronikapj
0
270
Go 1.27 における memory allocation の高速化
andpad
0
290
Detecting Compromised CI with eBPF and Cilium Tetragon
lizrice
0
230
Featured
See All Featured
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
450
AI: The stuff that nobody shows you
jnunemaker
PRO
9
930
WENDY [Excerpt]
tessaabrams
11
39k
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.1k
Build your cross-platform service in a week with App Engine
jlugia
234
19k
Agile that works and the tools we love
rasmusluckow
331
22k
Typedesign – Prime Four
hannesfritz
42
3.1k
For a Future-Friendly Web
brad_frost
183
10k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.1k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Product Roadmaps are Hard
iamctodd
55
12k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.8k
Transcript
メール認証とRuby 2024/03/06 Gotanda.rb#57 ikaruga / Atsushi Katsuura 1
誰 ikaruga / Atsushi Katsuura GMOペパボ株式会社 EC事業部 CREチーム puts Resolv::DNS.new.getresources(
'me.ikaruga.org', Resolv::DNS::Resource::IN::TXT ).map(&:data) => ["GITHUB=ikaruga777", "TWITTER=@UVB_76", "WORK=GMO Pepabo Inc.", "
[email protected]
"] 2
https://support.google.com/a/answer/81126?hl=ja 3
4
メール認証のおさらい 色々要件はあったけど、基本SPF,DKIM,DMARC 全てはメールのなりすましを防ぐための仕組み 5
メールヘッダー 二種類のFrom ヘッダーFrom メールヘッダーの From エンベロープFrom メールヘッダーの Return-Path 6
(ちょうどいま来たメールを例に) Gmailだったらメールのメニューから「メッセージのソースを表示」をポチるとヘッダーを確 認できる # ヘッダーFrom From: Duolingo <
[email protected]
> # エンベロープFrom
Return-Path: <0100018e1341b06c-6b1b2b73-30d1-49fc-9788-8b3c5133d0c5-000000@bounces.duolingo.com> 7
SPF Sender Policy Framework メール送信元のドメインが許可されているかどうかをチェックする エンベロープFromのドメインでTXTレコード引くと v=spf1 から始まる値が取れる。 ip4: や
ip6: の後ろにIPアドレスが含まれているので、そこで送信元のIPアドレ スが引けたらPASS $ dig spf-external.shop-pro.jp TXT +short "v=spf1 ip4:210.175.7.1/32 include:srs0260.cuenote.jp ~all 8
SPF IPアドレス以外にも a , mx , include , redirect の
mechanism ではドメインを指定 できる。 ドメインに当たったらそのドメインで再帰的にTXTレコードを引いていく。 ルックアップの回数は10回まで。 https://tex2e.github.io/rfc-translater/html/rfc7208.html 4.6.4. DNS Lookup Limits にその話がある 9
(Googleから来てたメールを例に取る) メールヘッダー Return-Path: <3H5XiZRAKCgozk8wox32-xy1ozv8qyyqvo.mywsuk14qkHHHqwksv.myw@scoutcamp.bounces.google.com> Received: from mail-sor-f69.google.com (mail-sor-f69.google.com. [209.85.220.69]) From:
Google Payments <
[email protected]
> 209.85.220.69 が送信元のIPアドレス 10
Return-PathのドメインでSPFを引くと $ dig 3h5xizrakcgozk8wox32- xy1ozv8qyyqvo.mywsuk14qkhhhqwksv.myw@scoutcamp.bounces.google.com TXT +short "v=spf1 redirect=_spf.google.com" $
dig _spf.google.com TXT +short $ dig _spf.google.com TXT +short "v=spf1 include:_netblocks.google.com include:_netblocks2.google.com include:_netblocks3.google.com ~all" $ dig _netblocks.google.com TXT +short "v=spf1 ip4:35.190.247.0/24 ..( 中略).. ip4:209.85.128.0/17 .... ~all" 11
(Googleから来てたメールを例に取る) irb(main):003> IPAddr.new('209.85.128.0/17').include?('209.85.220.69') => true 12
DKIM DomainKeys Identified Mail メールを送信する際にメールの内容を用いて署名を作って認証する仕組み 送信されるメールサーバに秘密鍵を保存する 生成された署名は DKIM-Signature ヘッダーに付与される 受信者はメールヘッダーの
DKIM-Signature ヘッダーの d, s タグからレコードを見つ ける dはドメイン、sはセレクタ(鍵ローテのために複数認証系を用意してる) "#{s}._domainkey.#{d} でTXTレコードを引くと公開鍵が引けるので、それを使 って認証する。 13
(Googleから来てたメールを例に取る) メールヘッダー DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1709348127; x=1709952927;
dara=google.com; h=to:from:subject:message-id:feedback-id:reply-to:date:mime-version :from:to:cc:subject:date:message-id:reply-to; "#{s}._domainkey.#{d}" でTXTレコードを引く p= のあとが公開鍵 $ dig 20230601._domainkey.google.com TXT +short "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AM...( 略)" 14
DMARC Domain-based Message Authentication, Reporting and Conformance SPFとDKIMに加えて追加の認証をすることでなりすましを防ぐ SPFアライメント、DKIMアライメントを追加で認証する さらに、認証が通らなかったときのメールの監視の仕組みも定義されていて、送信元の
サーバー管理者が通告されたSPAMと判定されたメールの内容について把握することが できる。 設定もDNSレコードで行う 15
DMARCレコードの実例 $ dig _dmarc.google.com TXT +short "v=DMARC1; p=reject; rua=mailto:
[email protected]
" $
dig _dmarc.shop-pro.jp TXT +short "v=DMARC1; p=none; pct=100; adkim=r; aspf=r; rua=mailto:
[email protected]
; ruf=mailto:
[email protected]
;" 16
アライメント SPFアライメント エンベロープFromとヘッダーFromのドメインが一致しているかどうか DKIMアライメント ヘッダーFromのドメインと DKIM-Signature ヘッダーの d タグのドメインが一致している かどうか
17
ref: https://speakerdeck.com/azumakuniyuki/gu-iji-shu-nituite-smtpxian-dai-shi-qing- tumamishi-i?slide=14 YAPC::HiroshimaでされていたSMTPのセッションが簡潔にまとまっていて最高。 古い技術について—SMTP現代事情つまみ食い— - Speaker Deck 18
ブログ SendGrid, ベアメールのブログにわかりやすい記事がたくさんあって便利。 https://sendgrid.kke.co.jp/blog/ https://baremail.jp/blog/ 19
一応Rubyの話 20
設定されていることをどうやって確認するか SPF, DKIM, DMARCいずれもDNSレコードの内容を確認していく必要がある。 21
Resolv 標準ライブラリにDNS引いてくれるくんがいて便利。 https://github.com/ruby/resolv https://docs.ruby-lang.org/ja/3.3/library/resolv.html 22
誰 ikaruga / Atsushi Katsuura GMOペパボ株式会社 EC事業部 CREチーム puts Resolv::DNS.new.getresources(
# ← これ 'me.ikaruga.org', # ← これ Resolv::DNS::Resource::IN::TXT # ← これ ).map(&:data) # ← これ => ["GITHUB=ikaruga777", "TWITTER=@UVB_76", "WORK=GMO Pepabo Inc.", "
[email protected]
"] 23
パーサーがある https://github.com/trailofbits/spf-query SPFレコードのパーサーもいて便利 https://github.com/trailofbits/dkim-query DKIMレコードのパーサーもいて便利 https://github.com/trailofbits/dmarc DMARCレコードのパーサーもいて便利 24
spf-query 使ってみる require 'bundler/inline' gemfile do source 'https://rubygems.org' gem 'spf-query'
end domain = ARGV.first q = SPF::Query::Record.query(domain) def query(q, lookup_count) q.mechanisms.each do |mechanism| case mechanism.name when :ip4, :ip6 puts mechanism.value when :include, :redirect lookup_count += 1 return if lookup_count > 10 puts ">>" + mechanism.value # _spf サブドメインを暗黙的に引いてしまうらしい # https://github.com/trailofbits/spf-query/issues/10 records = Resolv::DNS.new.getresources(mechanism.value, Resolv::DNS::Resource::IN::TXT) spf_record = records.find do |record| record.strings.join.include?('v=spf1') end spf_record_value = spf_record.strings.join q = SPF::Query::Parser.parse(spf_record_value) query(q, lookup_count) when :a lookup_count += 1 # Resolv::DNS::Resource::IN::A でレコードを引く when :mx lookup_count += 1 # Resolv::DNS::Resource::IN::MX でレコードを引く when :ptr, :exsists lookup_count += 1 # 頑張って実装 end end end query(q, 0) 25
$ ruby parse_spf.rb _spf.google.com >>_netblocks.google.com 35.190.247.0/24 64.233.160.0/19 66.102.0.0/20 66.249.80.0/20 72.14.192.0/18
74.125.0.0/16 108.177.8.0/21 173.194.0.0/16 209.85.128.0/17 216.58.192.0/19 216.239.32.0/19 >>_netblocks2.google.com 2001:4860:4000::/36 2404:6800:4000::/36 2607:f8b0:4000::/36 2800:3f0:4000::/36 2a00:1450:4000::/36 2c0f:fb50:4000::/36 >>_netblocks3.google.com 172.217.0.0/19 172.217.32.0/20 172.217.128.0/19 172.217.160.0/20 172.217.192.0/19 172.253.56.0/21 172.253.112.0/20 108.177.96.0/19 35.191.0.0/16 130.211.0.0/22 26
まとめ 最近話題になっていたDNSを使ったメール認証のしくみのおさらいをしました Rubyでドメインに対して適切なレコードが設定されているかを確認するを1つ紹介しま した 懇親会で喋れたら喋りたい ワンクリック購読解除の適用範囲 27
仕事の話(宣伝) 3/15~の Ya8 2024 - ヤパチー 令和六年最新版(仮) で同僚が現場の話をする予定です(採択さ れていました) 以下のような現場の話が聞ける可能性があります
「メールサーバー」を自前で運用している 自前のメールサーバーやSaasを通して、ユーザーが設定した「独自ドメイン」でメール を送るための機能を提供している https://github.com/hachiojipm/ya8-2024-cfp/issues/32 28