Skip to content

メールアドレス vs 俺たち

公開日:

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

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