Slide 1

Slide 1 text

FQDN(ドメイン名)のバリ デーションが意外と面倒 だった PHP Conference Japan 2022 September 24 - 25, 2022.

Slide 2

Slide 2 text

@akase244 var_dump( (new Me()) ->WebApplicationEngineer() ->InfrastructureEngineer() ); 2

Slide 3

Slide 3 text

なぜドメイン名の バリデーションをやりたかったのか? 3

Slide 4

Slide 4 text

ドメイン名の入力 4

Slide 5

Slide 5 text

こんな入力を防ぎたい 5 ● www.example,com 「カンマ」を含んでいる ● www.example com 「空白」を含んでいる ● www.examp!e.com 「エクスクラメーション」を含んでいる ● www.example.com 「ドメイン名」が含まれていない

Slide 6

Slide 6 text

filter_varを発見 6

Slide 7

Slide 7 text

7 ● FILTER_VALIDATE_BOOL (= FILTER_VALIDATE_BOOLEAN) ● FILTER_VALIDATE_DOMAIN ● FILTER_VALIDATE_EMAIL ● FILTER_VALIDATE_FLOAT ● FILTER_VALIDATE_INT ● FILTER_VALIDATE_IP ● FILTER_VALIDATE_MAC ● FILTER_VALIDATE_REGEXP ● FILTER_VALIDATE_URL 検証フィルタ

Slide 8

Slide 8 text

FILTER_VALIDATE_DOMAIN にそれっぽい説明 8

Slide 9

Slide 9 text

9 試してみた

Slide 10

Slide 10 text

「カンマ」が含まれている 10 $ docker container run \ --rm -it php:8.1.10-cli-alpine \ php -r 'var_dump( filter_var( "www.example,com", FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME ) );' bool(false)

Slide 11

Slide 11 text

「空白」が含まれている 11 $ docker container run \ --rm -it php:8.1.10-cli-alpine \ php -r 'var_dump( filter_var( "www.example com", FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME ) );' bool(false)

Slide 12

Slide 12 text

「エクスクラメーション」が含まれ ている 12 $ docker container run \ --rm -it php:8.1.10-cli-alpine \ php -r 'var_dump( filter_var( "www.examp!e.com", FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME ) );' bool(false)

Slide 13

Slide 13 text

13 完

Slide 14

Slide 14 text

「ドメイン名」が含まれていない 14 $ docker container run \ --rm -it php:8.1.10-cli-alpine \ php -r 'var_dump( filter_var( "www", FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME ) );' string(3) "www"

Slide 15

Slide 15 text

FILTER_FLAG_HOSTNAME の説明を思い出してみる 15

Slide 16

Slide 16 text

FILTER_FLAG_HOSTNAME の説明を思い出してみる 16 FILTER_FLAG_HOSTNAME を使うと、 ホス ト名 (アルファベットか数字で始まり、 アル ファベットか数字、もしくはハイフンのみが 含 まれている必要があります) も追加で検証で きます。

Slide 17

Slide 17 text

17 ホスト名ってどういうものだっけ?

Slide 18

Slide 18 text

ホスト名ってこういうもの 18 ● localhost ● mail ● app ● www

Slide 19

Slide 19 text

FILTER_FLAG_HOSTNAME を指定して実行 19 $ docker container run \ --rm -it php:8.1.10-cli-alpine \ php -r 'var_dump( filter_var( "localhost", FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME ) );' string(9) "localhost"

Slide 20

Slide 20 text

20 そもそもドメイン名としてあるべき姿とは?

Slide 21

Slide 21 text

ここにヒントがありそう 21

Slide 22

Slide 22 text

ここにヒントがありそう 22 ドメイン名が RFC 1034, RFC 1035, RFC 952, RFC 1123, RFC 2732, RFC 2181, RFC 1123 に照らして正しいかを 検証します。

Slide 23

Slide 23 text

ドメイン名のバリデーションに関係しそう なRFCを読んでみた 23 ● RFC 952 (DOD INTERNET HOST TABLE SPECIFICATION) ● RFC 1034 (DOMAIN NAMES - CONCEPTS AND FACILITIES) ● RFC 1035 (DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION) ● RFC 1123 (Requirements for Internet Hosts -- Application and Support) ● RFC 2181 (Clarifications to the DNS Specification)

Slide 24

Slide 24 text

RFC 952 (DOD INTERNET HOST TABLE SPECIFICATION) 24 ● ASSUMPTIONS ○ A "name" (Net, Host, Gateway, or Domain name) is a text string up to 24 characters drawn from the alphabet (A-Z), digits (0-9), minus sign (-), and period (.). Note that periods are only allowed when they serve to delimit components of "domain style names". (See RFC-921, "Domain Name System Implementation Schedule", for background). ○ No blank or space characters are permitted as part of a name. ○ No distinction is made between upper and lower case. ○ The first character must be an alpha character. ○ The last character must not be a minus sign or period.

Slide 25

Slide 25 text

25 ● 3.1. Name space specifications and terminology ○ The most common interpretation uses the root "." as either the single origin or as one of the members of the search list, so a multi-label relative name is often one where the trailing dot has been omitted to save typing. RFC 1034 (DOMAIN NAMES - CONCEPTS AND FACILITIES)

Slide 26

Slide 26 text

26 ● 2.3.1. Preferred name syntax ○ The labels must follow the rules for ARPANET host names. They must start with a letter, end with a letter or digit, and have as interior characters only letters, digits, and hyphen. There are also some restrictions on the length. Labels must be 63 characters or less. ● 2.3.4. Size limits ○ Various objects and parameters in the DNS have size limits. They are listed below. Some could be easily changed, others are more fundamental. ■ labels 63 octets or less ■ names 255 octets or less ● 3.1. Name space definitions ○ Since every domain name ends with the null label of the root, a domain name is terminated by a length byte of zero. ○ To simplify implementations, the total length of a domain name (i.e., label octets and label length octets) is restricted to 255 octets or less. RFC 1035 (DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION)

Slide 27

Slide 27 text

27 ● 2.1 Host Names and Numbers ○ The syntax of a legal Internet host name was specified in RFC-952 [DNS:4]. One aspect of host name syntax is hereby changed: the restriction on the first character is relaxed to allow either a letter or a digit. Host software MUST support this more liberal syntax. ○ Host software MUST handle host names of up to 63 characters and SHOULD handle host names of up to 255 characters. RFC 1123 (Requirements for Internet Hosts -- Application and Support)

Slide 28

Slide 28 text

28 ● 11. Name syntax ○ The length of any one label is limited to between 1 and 63 octets. ○ A full domain name is limited to 255 octets (including the separators). ○ The zero length full name is defined as representing the root of the DNS tree, and is typically written and displayed as ".". RFC 2181 (Clarifications to the DNS Specification)

Slide 29

Slide 29 text

29 完全に理解した

Slide 30

Slide 30 text

30 ● ドメイン名は253文字以下でなければならない(最大長の 255オクテット - 予約分の2オクテット) ○ ドメイン名の表記は末尾のドットが省略されていることが 多い(予約分の1オクテット) ○ すべてのドメイン名はrootのnullラベルで終了する(予約 分の1オクテット) ドメイン名とは?

Slide 31

Slide 31 text

31 ● ラベルに利用可能な文字 ○ 英字(A-Z(大文字、小文字の区別はなし)) ○ 数字(0-9) ○ マイナス記号(ハイフン) ドメイン名とは?

Slide 32

Slide 32 text

32 ● ラベルは63文字以下でなければならない ○ ラベルの最初及び最後の文字は英数字でなければなら ない ○ ラベルの最初及び最後の文字としてマイナス記号は利用 できない ○ ドットは区切り文字なのでラベルとしては利用できない ドメイン名とは?

Slide 33

Slide 33 text

文章ではわかりづらいので 実際にDNSに登録してみた 33

Slide 34

Slide 34 text

ドメイン名が253文字以下は 34 $ echo -n 'www.www.www.www.www.www.www.www.www.www.www.www.w ww.www.www.www.www.www.www.www.www.www.www.www.www .www.www.www.www.www.www.www.www.www.www.www.www.w ww.www.www.www.www.www.www.www.www.www.www.www.www .www.www.www.www.www.www.www.www.www.www.ww.tsunag i.me'|wc -c 253

Slide 35

Slide 35 text

利用可能 35 $ dig www.www.www.www.www.www.www.www.www.www.www.www.ww w.www.www.www.www.www.www.www.www.www.www.www.www. www.www.www.www.www.www.www.www.www.www.www.www.ww w.www.www.www.www.www.www.www.www.www.www.www.www. www.www.www.www.www.www.www.www.www.www.ww.tsunagi .me +short 75.2.60.5

Slide 36

Slide 36 text

ドメイン名が254文字以上は 36 $ echo -n 'www.www.www.www.www.www.www.www.www.www.www.www.w ww.www.www.www.www.www.www.www.www.www.www.www.www .www.www.www.www.www.www.www.www.www.www.www.www.w ww.www.www.www.www.www.www.www.www.www.www.www.www .www.www.www.www.www.www.www.www.www.www.www.tsuna gi.me'|wc -c 254

Slide 37

Slide 37 text

利用不可 37 $ dig www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.w ww.www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.ww w.www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.www .www.www.www.www.www.www.www.www.www.tsunagi.me +shortdig: 'www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.www. www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.w ww.www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.www.ww w.www.www.www.www.www.www.www.www.www.tsunagi.me' is not a legal IDNA2008 name (domain name longer than 255 characters), use +noidnin

Slide 38

Slide 38 text

ラベルが63文字以下は 38 $ echo -n 'wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww wwwwwwwwwwwwww' |wc -c 63

Slide 39

Slide 39 text

利用可能 39 $ dig wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww wwwwwwwwwwwwww.tsunagi.me +short 75.2.60.5

Slide 40

Slide 40 text

ラベルが64文字以上は 40 $ echo -n 'wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww wwwwwwwwwwwwwww' | wc -c 64

Slide 41

Slide 41 text

利用不可 41 $ dig wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww wwwwwwwwwwwwww.tsunagi.me +short dig: 'wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww wwwwwwwwwwwwwww.tsunagi.me' is not a legal IDNA2008 name (domain label longer than 63 characters), use +noidnin

Slide 42

Slide 42 text

英字、数字、マイナス記号が ラベルの文字列として利用可能 42 $ dig abc-123.tsunagi.me +short 75.2.60.5 $ dig abcdefghijklmnopqrstuvwxyz-1234567890.tsunagi.me +short 75.2.60.5

Slide 43

Slide 43 text

43 ドメイン名がどういうものかは理解した

Slide 44

Slide 44 text

44 ● ドメイン名は253文字以下でなければならない(最大長の 255オクテット - 予約分の2オクテット) ○ ドメイン名の表記は末尾のドットが省略されていることが多い(予約分の 1オクテット) ○ すべてのドメイン名は rootのnullラベルで終了する(予約分の 1オクテット) ● ラベルに利用可能な文字 ○ 英字(A-Z(大文字、小文字の区別はなし)) ○ 数字(0-9) ○ マイナス記号(ハイフン) ● ラベルは63文字以下でなければならない ○ ラベルの最初及び最後の文字は英数字でなければならない ○ ラベルの最初及び最後の文字としてマイナス記号は利用できない ○ ドットは区切り文字なのでラベルとしては利用できない しかし、このバリデーション の実装は面倒

Slide 45

Slide 45 text

では、filter_var の FILTER_VALIDATE_DOMAIN は具体的に 何をチェックしているんだろう? 45

Slide 46

Slide 46 text

/php-8.1.10/ext/filter/logical_filters.c を読んでみた 46

Slide 47

Slide 47 text

47 507 static int _php_filter_validate_domain(char * domain, size_t len, zend_long flags) /* {{{ */ 508 { ・ ・ 525 /* The total length cannot exceed 253 characters (final dot not included) */ 526 if (l > 253) { 527 return 0; 528 } ドメイン名は253文字以下 254文字以上はfalse

Slide 48

Slide 48 text

48 507 static int _php_filter_validate_domain(char * domain, size_t len, zend_long flags) /* {{{ */ 508 { ・ ・ 519 /* Ignore trailing dot */ 520 if (l > 0 && *t == '.') { 521 e = t; 522 l--; 523 } 末尾のドットを省略 末尾のドットは無視する (RFCの仕様通り)

Slide 49

Slide 49 text

49 507 static int _php_filter_validate_domain(char * domain, size_t len, zend_long flags) /* {{{ */ 508 { ・ ・ ・ 530 /* First char must be alphanumeric */ 531 if(*s == '.' || (hostname && !isalnum((int)*(unsigned char *)s))) { 532 return 0; 533 } ラベルの最初及び最後の文字 は英数字 最初の文字が「.」(ドット)または英数 字以外の場合はfalse

Slide 50

Slide 50 text

535 while (s < e) { 536 if (*s == '.') { 537 /* The first and the last character of a label must be alphanumeric */ 538 if (*(s + 1) == '.' || (hostname && (!isalnum((int)*(unsigned char *)(s - 1)) || !isalnum((int)*(unsigned char *)(s + 1))))) { 539 return 0; 540 } ・ ・ 50 ラベルの最初及び最後の文字 は英数字 最初及び最後の文字が「.」(ドット)または 英数字以外の場合はfalse

Slide 51

Slide 51 text

51 535 while (s < e) {                ・                ・ 544 } else { 545 if (i > 63 || (hostname && *s != '-' && !isalnum((int)*(unsigned char *)s))) { 546 return 0; 547 }                ・                ・ ラベルは英数字、ハイフン 63文字以下 ラベルが64文字以上、または、 英数字、ハイフン以外はfalse

Slide 52

Slide 52 text

52 ● ドメイン名は253文字以下でなければならない(最大長の 255オクテット - 予約分の2オクテット) ○ ドメイン名の表記は末尾のドットが省略されていることが多い(予約分の 1オクテット) ○ すべてのドメイン名は rootのnullラベルで終了する(予約分の 1オクテット) ● ラベルに利用可能な文字 ○ 英字(A-Z(大文字、小文字の区別はなし)) ○ 数字(0-9) ○ マイナス記号(ハイフン) ● ラベルは63文字以下でなければならない ○ ラベルの最初及び最後の文字は英数字でなければならない ○ ラベルの最初及び最後の文字としてマイナス記号は利用できない ○ ドットは区切り文字なのでラベルとしては利用できない あれ?全部網羅されている

Slide 53

Slide 53 text

filter_var、疑ってゴメンなさい 53

Slide 54

Slide 54 text

今回必要なバリデーションの仕様としては ・ホスト名のみ(ドメイン名を含まない)はNG ・ネイキッドドメイン(Zone Apex)のみはOK この条件を満たせばよいことがわかったので 54

Slide 55

Slide 55 text

55 バリデーションの例 = 2) && filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) ); } var_dump(validate('www')); // false var_dump(validate('www.example.com')); // true var_dump(validate('www.example,com')); // false var_dump(validate('www.example com')); // false var_dump(validate('www.examp!e.com')); // false 「.」(ドット)で区切られた数が 2以上の場合という条件を追加

Slide 56

Slide 56 text

ここまで話した内容は 56

Slide 57

Slide 57 text

ひさてるさん(@tanakahisateru)が 7年前に詳しく解説されています 57 ● http:/ /blog.a-way-out.net/blog/2015/02/16/validate-hostname/

Slide 58

Slide 58 text

DNSに登録されている ドメイン名であれば 58 おまけ1

Slide 59

Slide 59 text

checkdnsrr 59 $ docker container run \ --rm -it php:8.1.10-cli-alpine \ php -r 'var_dump( checkdnsrr("twitter.com", "A") );' bool(true)

Slide 60

Slide 60 text

filter_var / FILTER_VALIDATE_IP gethostbyname 60 $ docker container run \ --rm -it php:8.1.10-cli-alpine \ php -r 'var_dump( filter_var( gethostbyname("twitter.com"), FILTER_VALIDATE_IP ) );' string(12) "104.244.42.1"

Slide 61

Slide 61 text

といったチェック方法もあります 61

Slide 62

Slide 62 text

Qiitaにまとめました 62 おまけ2

Slide 63

Slide 63 text

【 tsunagi.me 】 というドメインでPodcastを やってるので聞いてください 63 最後に宣伝

Slide 64

Slide 64 text

今回話さなかったことについて 64

Slide 65

Slide 65 text

65 皆が本当に 聞きたいのはこれでしょ? PHPカンファレンス福岡2023の 開催可否については委員長まで @seike460

Slide 66

Slide 66 text

Thanks! Have a good programming!! 66