Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/content/blog-metas/2024-12-03-ssh.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"postDate": "2024-12-02T09:54:41.345Z"
"postDate": "2024-12-02T09:54:41.345Z",
"updateDate": "2024-12-06T14:48:00.489Z"
}
3 changes: 2 additions & 1 deletion src/content/blog-metas/2024-12-04-slack.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"postDate": "2024-12-03T15:04:44.892Z"
"postDate": "2024-12-03T15:04:44.892Z",
"updateDate": "2024-12-06T14:48:00.490Z"
}
3 changes: 2 additions & 1 deletion src/content/blog-metas/2024-12-05-omron.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"postDate": "2024-12-04T15:04:39.878Z"
"postDate": "2024-12-04T15:04:39.878Z",
"updateDate": "2024-12-06T14:48:00.490Z"
}
3 changes: 2 additions & 1 deletion src/content/blog-metas/2024-12-06-mail.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"postDate": "2024-12-05T15:09:19.847Z"
"postDate": "2024-12-05T15:09:19.847Z",
"updateDate": "2024-12-06T14:48:00.491Z"
}
2 changes: 1 addition & 1 deletion src/content/blogs/2024-12-03-ssh.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ tags: [advent-calendar]

![](2024-12-03-ssh/kc3hack.jpg)

閑話休題。私は今では大学院にいるわけですが、そうなるともちろん研究室に所属しています。で、研究室って、膨大な量の研究関連データがあり、しかも性質上あまり外には出せないので、割とオンプレでサーバを持っています。そして、その管理は研究室によるものの、学生が管理していることも多いです。さらに、うちの大学は[歴史的経緯](https://pentan.info/doc/ip133_list.html)で IPv4 アドレスを大量に持っている(`133.1.0.0/16`)ので、研究室ごとに複数の IPv4 アドレスを持っている極めて特異な環境です(つまり、サーバとルータの両方に global アドレスを振れる)。例に漏れず私は研究室のサーバを管理する担当になり、また丁度筐体の入れ替え時期だったこともあり、現在の基幹サーバ(`sel.ist.osaka-u.ac.jp`)をフルスクラッチで構築しました。外から見えるのは [Web サイト](https://sel.ist.osaka-u.ac.jp/)ぐらいかもしれませんが(これも PHP やら CGI やら VirtualHost やら色々動いているので結構大規模)、それ以外にも色々と動いています。その過程で色々と得た知見があるので、それを少し出してみます。まずは、SSH の話題。
閑話休題。私は今では大学院にいるわけですが、そうなるともちろん研究室に所属しています。で、研究室って、膨大な量の研究関連データがあり、しかも性質上あまり外には出せないので、割とオンプレでサーバを持っています。そして、その管理は研究室によるものの、学生が管理していることも多いです。さらに、うちの大学は[歴史的経緯](https://pentan.info/doc/ip133_list.html)で IPv4 アドレスを大量に持っている(`133.1.0.0/16`)ので、研究室ごとに複数の IPv4 アドレスを持っている極めて特異な環境です(つまり、サーバとルータの両方に global アドレスを振れる)。例に漏れず私は研究室のサーバを管理する担当になり、また丁度筐体の入れ替え時期だったこともあり、現在の基幹サーバ(`sel.ist.osaka-u.ac.jp`)をフルスクラッチで構築しました。さすがに Web コンテンツは旧サーバから転送してきたものですが、PHP やら CGI やら VirtualHost やら色々使われているので正常に動作する基盤を組むのは割と大変でした。外から見えるのはそんな [Web サイト](https://sel.ist.osaka-u.ac.jp/)ぐらいかもしれませんが、それ以外にも色々と動いています。その過程で色々と得た知見があるので、それを少し出してみます。まずは、SSH の話題。

SSH を使うと、暗号通信を使って安全にリモートコンピュータに接続できます。断じて科学教育に注力する高校 (Super Science High-school) のことではありません。そんな SSH ですが、その機能は Shell だけではなく、リモートコンピュータとの通信路(トンネル)を形成し、SSH 以外のサービスについてもリモートアクセスを提供することができます。**なお、この記事は SSH やネットワークについて一定の知識を持っている人を対象としています。環境や設定によってはセキュリティ上の懸念が生じるので、内容を理解できる方のみ自己責任で試してください。**

Expand Down
2 changes: 1 addition & 1 deletion src/content/blogs/2024-12-04-slack.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ tags: [advent-calendar, shell]
1. 返ってきた JSON を解析して `upload_url` と `file_id` を得る
1. `upload_url` に対して `POST` でファイルを送る
1. [`files.completeUploadExternal`](https://api.slack.com/methods/files.completeUploadExternal) に `POST` で以下の情報を送る
- Bot token (HTTP Header `Authorization: Bearer`)
- Bot token (HTTP Header `Authorization: Bearer xxxx`)
- `file_id` (HTTP Body JSON `files` list)(複数可)
- 送信先 channel の ID (HTTP Body JSON `channel_id`)
- 本文の内容 (HTTP Body JSON `initial_comment`)
Expand Down
4 changes: 2 additions & 2 deletions src/content/blogs/2024-12-05-omron.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ USB メモリに似た小さなデバイスで、色々なデータを USB シ

## udev

初期状態では Linux kernel に環境センサの情報が登録されていないため、接続しても認識されません。そこでudev rule を設定します。設定するといっても、やることは以下の内容のテキストファイルを `/etc/udev/rules.d/99-omron.rules` みたいな名前で作成するだけです。
初期状態では Linux kernel に環境センサの情報が登録されていないため、接続しても認識されません。そこで udev rule を設定します。設定するといっても、やることは以下の内容のテキストファイルを `/etc/udev/rules.d/99-omron.rules` みたいな名前で作成するだけです。

```
ACTION=="add", \
Expand Down Expand Up @@ -62,7 +62,7 @@ Data frame の形式は以下の通りで、frame 開始を告げる Frame heade
)
ser.write(command + crc16(command))
```
- データの読み出しなので Read コマンド (`0x01`) で、さらにアドレスとして実際のコマンド Latest data long (`0x5021`) を指定する
- データの読み出しなので Read コマンド (`0x01`) で、さらにアドレスとして実際のコマンド Latest data long (`0x5021`) を指定する
1. 1 秒待つ
1. 結果を受信する

Expand Down
50 changes: 36 additions & 14 deletions src/content/blogs/2024-12-06-mail.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ tags: [advent-calendar]

この記事は [OUCC Advent Calendar 2024](https://adventar.org/calendars/10655) の 6 日目の記事です。昨日は [OMRON 環境センサ 2JCIE-BU を Prometheus で使う](../2024-12-05-omron/)方法を解説しました。本日は、メールサーバを送信側として SPF/DKIM/DMARC 対応させる方法を説明します。受信側は結構ややこしいことと、完全に自衛目的となり他人にとっては関係ないのでここでは扱いません。

メールというものは容易に偽装が可能なプロトコルだという点はご存知でしょうか。顕著な例として、差出人欄にはどんな文字列でも書き込むことができます。これはつまり、**誰でも政府機関、著名企業、著名人を名乗ってメールを送信できる**ということを表します。また、**途中の中継サーバで内容を勝手に書き換えることも可能です**。どうしてそんなひどいプロトコルなのかというと、当初は研究者間でメッセージをやり取りするだけの簡易的な仕組みだった(SMTP は **Simple** Mail Transfer Protocol の略)というのがあると思いますが、仕様的には郵便に似せた面も大きいのではないかと思います。例えば、差出人は SMTP では Envelope From と Header From がありますが、これらは郵便における「封筒に書く差出人」と「封筒の中の手紙に書いた差出人」に対応します。よくよく考えてみると、郵便であっても差出人に嘘を書くことは容易です(改竄は微妙ですが...)。そうした点からも、こういうプロトコル仕様になっているのではないかと思います。
メールというものは容易に偽装が可能なプロトコルだという点はご存知でしょうか。顕著な例として、差出人欄にはどんな文字列でも書き込むことができます。これはつまり、**誰でも政府機関、著名企業、著名人を名乗ってメールを送信できる**ということを表します。また、**途中の中継サーバで内容を勝手に書き換えることも可能です**。どうしてそんなひどいプロトコルなのかというと、当初は研究者間でメッセージをやり取りするだけの簡易的な仕組みだった(SMTP は **Simple** Mail Transfer Protocol の略)というのがあると思いますが、仕様的には郵便に似せた面も大きいのではないかと思います(そもそも "mail" という語自体が「郵便」という意味)。例えば、差出人は SMTP では Envelope From と Header From がありますが、これらは郵便における「封筒に書く差出人」と「封筒の中の手紙に書いた差出人」に対応します。よくよく考えてみると、郵便であっても差出人に嘘を書くことは容易です(改竄は微妙ですが...)。そうした点からも、こういうプロトコル仕様になっているのではないかと思います。

しかし、時代は進み、メールはもはや研究者間のものではなく、社会において公式的な重要な情報連絡手段となりました。金銭や個人情報が絡む場面で使われることも多くなり、当初のようなザルプロトコルのまま使うわけにはいかなくなりました。そうした事情から SPF/DKIM/DMARC をはじめとする数多の認証技術が開発され、実際に [Gmail が SPF/DKIM いずれかの認証通過を必須化した](https://support.google.com/a/answer/81126)ことが話題となりました。
しかし、時代は進み、メールはもはや研究者間だけのものではなく、社会において公式的な重要な情報連絡手段となりました。金銭や個人情報が絡む場面で使われることも多くなり、当初のようなザルプロトコルのまま使うわけにはいかなくなりました。そうした事情から SPF/DKIM/DMARC をはじめとする数多の認証技術が開発され、実際に [Gmail が SPF/DKIM いずれかの認証通過を必須化した](https://support.google.com/a/answer/81126)ことが話題となりました。

前提として、これらの技術を簡単に説明しておきます。今回は扱いませんが、ARC もおまけで説明しておきます。

- **SPF (Sender Policy Framework): 受信者がメールが正しいサーバから届いているかを検証(なりすまし対策)**
- 「このドメインのメールは必ずこのサーバから送る」という情報を、送信者が予め DNS の TXT レコードに置いておく
- 「このドメインのメールは必ずこのサーバから送る(それ以外はなりすまし)」という情報を、送信者が予め DNS の TXT レコードに置いておく
- **DKIM (DomainKeys Identified Mail): 送信者がメールに署名し、受信者が改竄の有無を検証(改竄対策)**
- 署名用秘密鍵に対応する公開鍵を、送信者が予め DNS の TXT レコードに置いておく
- **DMARC (Domain-based Message Authentication, Reporting, and Conformance): SPF/DKIM の検証失敗時に受信者が取るべき対応を送信者が指定**
Expand Down Expand Up @@ -54,7 +54,7 @@ sudo mkdir /var/spool/postfix/opendkim
sudo chown opendkim:opendkim /var/spool/postfix/opendkim
```

`/etc/opendkim/InternalHosts` に、検証対象から除外して逆に署名する対象を以下のように記載します。LAN 内の他のマシンからのメール送信を中継する場合は、そのサーバのアドレスも記載します。`192.168.0.0/16` のような CIDR 記法や `*.example.com` のようなホスト名も使えます。
`/etc/opendkim/InternalHosts` に、検証対象から除外して逆に署名する対象を以下のように記載します。LAN 内の他のマシンからのメール送信を中継する場合は、そのサーバのアドレスも記載します。`192.168.0.0/16` のような CIDR 記法や `.example.com` のようなホスト名も使えます(IPv6 も対応)

```text
127.0.0.1
Expand Down Expand Up @@ -117,17 +117,17 @@ sudo systemctl restart opendkim postfix

## DNS

ドメインが `mail.sample.com` であると仮定すると、以下の情報を登録することになります。公開鍵 `default.txt` が 3 行になっているのは DNS ソフトウェアの BIND 9 が 255 文字を超える文字列を扱えないためなので、そのままの形で登録してください。
メール送信元ドメインがそのまま DNS の管轄ドメインであれば、以下の情報を登録します。公開鍵 `default.txt` が 3 行になっているのは DNS ソフトウェアの BIND 9 が 255 文字を超える文字列を扱えないためなので、そのままの形で登録してください。

```
mail.sample.com IN TXT "v=spf1 ip4:メール送信元IPアドレス範囲 ~all"
default._domainkey.mail.sample.com IN TXT ( "v=DKIM1; h=sha256; k=rsa; " <- default.txt の公開鍵の内容 3 行をそのまま書く
@ IN TXT "v=spf1 ip4:メール送信元IPアドレス範囲 ~all"
default._domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; " <- default.txt の公開鍵の内容 3 行をそのまま書く
"p=..."
"..." )
_dmarc.mail.sample.com IN TXT "v=DMARC1; p=none"
_dmarc IN TXT "v=DMARC1; p=none"
```

なお、組織によっては `sample.com` のサブドメインを管轄する DNS を使っている場合もあるかと思いますが、その場合は以下のようになります。DKIM のドメイン部分が `default.txt` の書き方とは若干変わる形になるので注意してください。
組織によってはドメインを複数部署で共有しており、各部署がそれぞれのホスト名でメールサーバを持っていることもあると思います。そして、そのドメインを管轄する DNS にホスト名(ここでは `mail` とする)を登録する形の場合、登録する内容は以下のようになります。DKIM のドメイン部分が `default.txt` の書き方とは若干変わる形になるので注意してください。

```
mail IN TXT "v=spf1 ip4:メール送信元IPアドレス範囲 ~all"
Expand All @@ -144,18 +144,27 @@ _dmarc.mail IN TXT "v=DMARC1; p=none"
- **DKIM/DMARC: DKIM と DMARC の CNAME を書く**
- CNAME 先と書く内容を変えたい場合は普通に TXT レコードを置いてもよい

最初の例で言うと、`smtp.sample.com` という CNAME を持っている場合は以下の内容を記載します。
2 番目の例で言うと、ホスト名 `smtp` という CNAME を持っている場合は以下の内容を記載します(`mail` の FQDN が `mail.sample.com` だと仮定しています)

```
default._domainkey.smtp.sample.com IN CNAME default._domainkey.mail.sample.com.
_dmarc.smtp.sample.com IN CNAME _dmarc.mail.sample.com.
default._domainkey.smtp IN CNAME default._domainkey.mail.sample.com.
_dmarc.smtp IN CNAME _dmarc.mail.sample.com.
```

要するに、`ユーザ名@sample.com` のメールアドレスに対して SPF/DKIM/DMARC 対応させたい場合、

- **`sample.com` から SPF レコードを読める**
- **`セレクタ._domainkey.sample.com` から DKIM レコードを読める**
- **`_dmarc.sample.com` から DMARC レコードを読める**

状態になっていることが重要というわけです。

各エントリの意味は以下のとおりです。

- SPF
- ホスト自体に対する `TXT` レコードとして設定する
- `ip4:メール送信元IPアドレス範囲`: `mail.sample.com` の名でメールを送れる IPv4 アドレスは `メール送信元IPアドレス範囲`(CIDR 記法)だと受信者に公示
- `ip4:メール送信元IPアドレス範囲`: このドメインを称してメールを送れる IPv4 アドレスは `メール送信元IPアドレス範囲`(CIDR 記法)だけだと受信者に公示
- IPv6 アドレスは `ip6:` で書く
- `~all`: 上記のルールを破るメールは「怪しい」と見做すよう受信者に指示
- 諸々の要因で正当なメールで検証失敗することがあるので、詐称と断定(`-all`)はさせないのが普通
- DKIM
Expand All @@ -165,7 +174,7 @@ _dmarc.smtp.sample.com IN CNAME _dmarc.mail.sample.com.
- `p=none`: 検証失敗メールも通常通り受け付けるよう受信者に指示
- しばらく様子を見て問題なさそうなら `p=quarantine`(迷惑メールに振り分け)に変更するとよい

DMARC レコードに以下の内容を記述すると、一部のサービスから SPF/DKIM/DMARC 検証の成否具合を毎日受けられます(人間には優しくない XML 形式で送られてくるので [DMARC Report Analyzer](https://mxtoolbox.com/DmarcReportAnalyzer.aspx) などのサービスを使うと良い)。執筆時点では Gmail と Outlook で確認しています。
DMARC レコードに以下の内容を記述すると、一部のサービスから SPF/DKIM/DMARC 検証の成否具合を毎日受けられます(もちろん、それらのサービスに対してメールを送信していることが必要)。人間には優しくない XML 形式で送られてくるので [DMARC Report Analyzer](https://mxtoolbox.com/DmarcReportAnalyzer.aspx) などのサービスを使うと便利です。執筆時点では Gmail と Outlook で確認しています。

- `rua=mailto:[email protected]`: 検証状況日次レポートの返送先を `[email protected]` にする
- 返送先を DMARC レコードと同じドメインにしないと返してくれないので、`CNAME` ではなく個別に設定する必要がある
Expand All @@ -191,3 +200,16 @@ Outlook では上記サービスのような UI は用意されていないの
## おわりに

本日は、メールサーバを送信側として SPF/DKIM/DMARC 対応させる方法を説明しました。面倒ではありますが、これだけで自身が発するメールを偽物ではない正当なものだと示せると考えると、やる価値はあると思います。世のメールの SPF/DKIM/DMARC 対応化が進み、なりすましメールの被害が少なくなると良いですね。

ちなみに、一般のメールユーザという立場でも、動作確認で示した方法で他人から受け取ったメールの SPF/DKIM/DMARC 認証が通っているかどうかを確認できます。これらが落ちているからといって必ずしも不正なメールとは限らないし、逆にこれらが通っているからといって必ずしも正当なメールとは限りませんが、「`.go.jp` アドレスを名乗っている政府からのメールが認証に落ちている。これはなりすましではないか?」みたいな簡易的なチェックには使えます。

注意点として、

- メールが転送されている場合 SPF が落ちる場合がある
- 転送者と差出人が異なるため
- メーリングリストを通ると DKIM が落ちる場合がある
- 件名にメール番号を追加したり、フッタにメーリングリストの情報を記載したりすることがあり、これが改竄とみなされるため
- `[email protected] <[email protected]>` みたいに「差出人名としてメールアドレスっぽい文字列を設定される」ことは防げない
- SPF が通っていても、実際のメールアドレスまでちゃんと見ないと騙される

ということは念頭に置いておきましょう。