VS DMARC!!!!!!!!!!!!!!!!!!
誰uvb_76.icon
code:ruby
$ irb -rresolv
irb(main):001* puts Resolv::DNS.new.getresources(
irb(main):002* 'me.ikaruga.org',
irb(main):003* Resolv::DNS::Resource::IN::TXT
irb(main):004> ).map(&:data)
TWITTER=@UVB_76
WORK=GMO Pepabo Inc.
BLUESKY=@ikaruga.org
GITHUB=ikaruga777
=> nil
用語の整理から
メールヘッダー
エンベローブFrom
つまるところの Return-Path ヘッダー
ヘッダーFrom
つまるところの From ヘッダー
Sender Policy Framework
送信元と言っているドメインとドメインとIPが一致しているかを確認する
ip4, ip6 で指定されたアドレスが含まれているので、そこで送信元のIPアドレスが引けたらPASS
IPアドレス以外にも a, mx, include の mechanism ではドメインを指定できる。
ドメインに当たったらそのドメインで再帰的にTXTレコードを引いていく。
ルックアップの回数は10回まで。
4.6.4. DNS Lookup Limits にその話がある
DomainKeys Identified Mail
署名です。署名。
メール送るときにメールサーバーに秘密鍵をおいて、メールの内容から署名を作る
署名は DKIM-Signature ヘッダーに付与される
受信者はメールヘッダーの DKIM-Signature ヘッダーの d, s タグからレコードを見つける
dはドメイン、sはセレクタ(鍵ローテのために複数認証系を用意してる)
"#{s}._domainkey.#{d} でTXTレコードを引くと公開鍵が引けるので、それを使って認証する。
署名には2種類ある
作成者署名
メール送信者のドメインで署名する
DKIMの公開鍵は送信者ドメインのDNSサーバーのレコードに設定する
DMARCもPASSする
SendGridとかメール配信サービスはここらへんの設定手順をくれる
CNAME設定してね、ってやつがそれ
Sender Authenticationありがとう
第三者署名
外部のメール配信サービスのドメインで署名する
公開鍵もメール配信サービスのドメインのDNSサーバーのレコードに設定する(ていうかされている)
SendGridとかなにもしないとこれ
SendGridのドメインで署名される
ヘッダーFromのドメインが署名したドメインと一致しないのでDMARCとおらない
Domain-based Message Authentication, Reporting and Conformance
SPFとDKIMに加えて追加の認証をすることでなりすましを防ぐ。
SPFアライメント、DKIMアライメントを追加で認証する。
さらに、認証が通らなかったときのメールの監視の仕組みやレポートについても定義されていて、いい感じに設定すると送信元が迷惑メールの内容について把握することができる。
ヘッダーFromのドメインとDKM署名に含まれる署名と一致するか
https://gyazo.com/6702f10c2e058ff1ee6a49505819e72e
これがわかりやすすぎ。
Authenticated Received Chain
転送時にDKIMとは別に署名することで、受信時のDMARC認証と異なる送信先で認証結果を引き継ぐしくみ 以下のヘッダー3点セットが付与される
ARC-Authentication-Results
ARC-Seal
ARC-Message-Signature
YAPC::HiroshimaでされていたSMTPのセッションが簡潔にまとまっていて最高。
メール送るSaasのブログが異様に詳しいので便利。
Ruby便利情報
標準ライブラリにDNS引いてくれるくんがいて便利。
SPFレコードのパーサーもいて便利。
DKIMのパーサーもいて便利
DMARCのパーサーもいて便利
spf-query使ってみる
雑にやるならこんな感じでひけるんじゃないですかね。上記の_spfサブドメイン引く話があるので、再帰で引くならResolvをそのまま使う必要がありそう。
code:ruby
require 'bundler/inline'
gemfile do
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
lookup_count += 1
return if lookup_count > 10
puts ">>" + mechanism.value
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, :mx, :ptr, :redirect, :exsists
lookup_count += 1
# 頑張って実装
end
end
end
query(q, 0)
code:console
$ 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
DKIMに関しては署名するクンもいて便利