Skip to content

メールアドレス vs 俺たち

公開日:

札幌市中央区札幌市民交流プラザで開催された『PHPカンファレンス北海道2024 前夜祭』でレギュラートーク(20分)として発表しました。

Download PDF

スライドテキスト

Page 1

メールアドレス vs 俺たち

Our stand against the challenges posed by E-mail addresses

pixiv Inc.

USAMI Kenta

2024-01-12 Sapporo Community Plaza

PHPカンファレンス北海道2024 前夜祭

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE / にゃんだーすわん
  • ピクシブ株式会社 pixiv事業本部 Webエンジニアリングチーム PHPer
  • 2012年末から現職でPHPを書いているWebプログラマ
  • Emacs PHP Modeを開発しています (2017年-)
  • プログラミング言語にちょっとこだわりのある素人 (spcamp2010)
  • 2011年頃にPython札幌というコミュニティをやっていました

Page 3

今回のお題

Page 4

出典: Wikipedia: ID (2023-07-09T09:38:16版)

Page 5

出典: Wikipedia: デジタルアイデンティティ ( 2023-10-20T14:01:45版)

Page 6

今回はIDとは何か(本質)の話には深入りしません

Page 7

おことわり

発表者は現時点において現職のID設計判断や実装に関わっていません!

Page 8

ID、Auth、アカウント基盤などAAA(Authentication,Authorization, Accounting)は高度な専門技術領域

Page 9

発表のねらい

Page 10

今回のゴール

  • ただメールアドレスを扱うだけのよくある仕組みだとしても、考慮事項がいくつもあってシンプルな実装では済まない(こともある)こと
  • これらの考慮事項には唯一の正解はなく、ビジネス要件やユーザーのニーズに応じて取捨選択する必要があるということを理解し、必要十分なものを設計・実装できること

Page 11

ゴールではないこと

  • メールアドレスに関係しないアカウント設計の考慮事項
  • こう実装すれば間違いないという指針を提示すること
  • デジタルアイデンティティを完全理解してIDエキスパートになること
  • オブジェクト指向設計についてマスターすること
  • 今回提示することをそのまま実装するとユニットテストしにくい構造になる場合があるので、適切に依存を分割・注入することは読者への課題とする

Page 12

今回は専門職ではない我々が実装するためのお話をします

Page 13

初心者の方も怖がらずにお聞きください

Page 14

さて

Page 15

難しいことは置いておいてユーザーからメールアドレスを収集したい(せざるを得ない)ことは現代でも多い

Page 16

メールアドレスを何に使うか

  • マーケティング (メールによる告知など)
  • Webサービスのログイン機能のIDとして
  • Laravelのようなフレームワークは基本機能として持っていて、スキャッフォールド(コードの自動生成)で最低限のものは簡単に作れる(生成されるので実装の必要すらない)
  • ログイン通知 (心あたりのないログインでないかユーザ自身に知らせる)

Page 17

メールアドレスを何に使うか

  • アカウント登録させてマーケティングに活用…
  • 利用規約に同意させた上なら問題はないが、やりすぎは嫌われるので要注意
  • メールマガジンなど送りすぎてフィルタリングされてしまっては、本当に大事な連絡が届かなくなるのはよくない
  • 個人的な意見では、私信のような体裁や「あなただけ特別に…」のような文言のキャンペーンメールは非常にストレスが大きい

Page 18

個人的感情はおいといて

Page 19

DBに入れるだけだしフレームワークとか要らん

Page 20

ですよね?[要出典]

Page 21

すごくシンプルなログインシステムを作っていきましょう

Page 22

[要件1]変な形式の文字列が登録できないこと

Page 23

aaa@example,com

Page 24

example.com

Page 25

Page 26

ググったら最適解が出てくる良い時代…

Page 27

良くなかった時代とは

Page 28

Page 29

Page 30

どういうこと?

Page 31

そもそもメールアドレスとは

Page 32

tadsan@pixiv.com

Page 33

"tadsan"@pixiv.com

Page 34

<tadsan@pixiv.com>

Page 35

USAMI Kenta <tadsan@pixiv.com>

Page 36

どれも「メールアドレス」

Page 37

出典: Wikipedia: メールアドレス (2023-11-07T03:00:31版)

Page 38

メールアドレスとは

  • 特に断りがなければ tadsan@pixiv.com のような文字列を指す
  • RFC 5322ではaddr-specと呼ばれるもの
  • USAMI Kenta <tadsan@pixiv.com> のような、名前や <> を含んだものもメールアドレス
  • 先述のブログで「正規表現でマッチできない」と言われているのはこれを含めたメールアドレスのこと

Page 39

出典: Wikipedia: メールアドレス (2023-11-07T03:00:31版)

Page 40

一般的なメールアドレスを収集する用途でaddr-spec以外が必要になることはない

Page 41

基本的にaddr-specだけを相手にすればいいとわかった

Page 42

改めて

Page 43

ローカルパートドメイン名

tadsan@pixiv.com

Page 44

ローカルパートの制約

  • dot-atom形式 (いわゆる普通のメールアドレス)
  • ASCIIの英数文字 [a-zA-Z0-9]
  • ASCIIの記号 ! # $ % & ' * + - / = ? ^ _ ` { | } ~
  • . (ドット)は先頭と末尾以外に使用できるが、2個以上連続できない
  • 大文字小文字は区別する… が… 現実には区別せずに扱うサービスも
  • むしろ多数

Page 45

Page 46

RFC違反メールアドレス

  • 2009年頃まで一部の携帯キャリアで発行できていたメールアドレス
  • good..by..@example.com のようなアドレスが発行できた
  • 仕様違反のメールアドレスでも動作するサービスが存在していたが…
  • 2020年にiOS 14、2021年にSendGridで利用不可能に
  • quoted-string形式 "good..by.."@example.com に変換すれば合法だが、残念なことに受信側のメールサービスが対応している必要がある

Page 47

Page 48

Page 49

Page 50

PHPではこれを使えば安全!

Page 51

…ここまでに説明した範囲では

Page 52

[要件2]存在しないドメインのメールアドレス登録を弾きたい

Page 53

a@b.c

Page 54

filter_var('a@b.c',FILTER_VALIDATE_EMAIL)

Page 55

filter_var('a@b.c',FILTER_VALIDATE_EMAIL)// => "a@b.c"

Page 56

定石:入力されたアドレスに送信してメール内のコードを入力させる

Page 57

実メール送る前にどうしても確認したいのだとしましょう

Page 58

Page 59

DNSをチェックしよう

Page 60

Page 61

この方法で良いといえば良いだめといえばだめ

Page 62

(非常に言葉を濁す)

Page 63

メールはどうやって届くのか

  • 白ヤギさんと黒ヤギさんが… という話から始めると15分では無理
  • メールに関係するDNSレコードにはAとMXがある
  • メール配送の仕組みとしてはAレコードがあればいいのだが、今日の多くはメールアドレスのドメイン部分に対応したMXレコードがある
  • Aレコードしかないメールアドレスは個人や小規模なメールサーバの独自運用されている傾向にあるのでAレコードもサポートするかは各自判断

Page 64

DNSではなくSMTPでチェックする別解もあるが…

Page 65

(僕は運用経験がないので言葉を濁す)

Page 66

ついでにメールアドレス

Page 67

IPアドレス

a@0.0.0.0

Page 68

filter_var('a@0.0.0.0',FILTER_VALIDATE_EMAIL)

Page 69

filter_var('a@0.0.0.0',FILTER_VALIDATE_EMAIL)// => "a@0.0.0.0"

Page 70

ドメインがIP

Page 71

[要件3]メールアドレスの重複登録を弾きたい!

Page 72

DBに登録

Page 73

ユニークキー制約

Page 74

大勝利

Page 75

かと思いましたか?

Page 76

ローカルパートの制約

  • dot-atom形式 (いわゆる普通のメールアドレス)
  • ASCIIの英数文字 [a-zA-Z0-9]
  • ASCIIの記号 ! # $ % & ' * + - / = ? ^ _ ` { | } ~
  • . (ドット)は先頭と末尾以外に使用できるが、2個以上連続できない
  • 大文字小文字は区別する… が… 現実には区別せずに扱うサービスも
  • むしろ多数

Page 77

a@example.com

Page 78

A@example.com

Page 79

同一かもしれないし別人かもしれない

Page 80

Page 81

unicode_ciは大文字小文字を同一視する

Page 82

utf8mb4_binで厳密チェックすればいいのか?

Page 83

もっとひどい穴を簡単に作れるのでbinで比較はやめた方がいいと思う

Page 84

Laravelは全部小文字のアドレスのみ許可(これが無難)

Page 85

この問題を騙り尽すには15分枠はあまりに短い…

Page 86

Gmailエイリアス沼

  • 同じメールアカウントに対応するアドレスはたくさんある
  • fafnir127@gmail.com, fafnir127+alias@gmail.com
  • f.a.f.n.i.r.1.2.7@gmail.com, fafnir127@googlemail.com
  • これらはGoogle Workspaceを使った独自ドメインのメールでも有効

Page 87

Page 88

ご静聴ありがとうございました