ホスト名バリデーションのやり方

(Last Updated On: 2018年8月13日)

徳丸さんのブログで私のブログ「GHOSTを使って攻撃できるケース」にコメントがあったようなので、好ましいホスト名バリデーションの方法を書いておきます。

特定の低レベルAPIのバグが10年ほど前に書いた本のコードで対応できていない、と議論するのもどうかと思いますがしっかりチェックする場合の例を書いておきます。

そもそもホスト名の仕様はどうなっているのか?

入力バリデーションを行うには仕様を理解する必要があります。ホスト名の仕様は幾つかのRFCで言及されています。例えば、RFC 2181の11. Name syntaxには

That one restriction
relates to the length of the label and the full name. 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).

と書かれています。つまり、ホスト名を構成する部品(.で分けられたラベル)は最小1バイト、最大63バイト、ホスト名全体では255バイトが最大になります。

そもそもの定義であるRFC 1123では次のように記述されています。

Host software MUST handle host names of up to 63 characters and
SHOULD handle host names of up to 255 characters.

その次には

Whenever a user inputs the identity of an Internet host, it SHOULD
be possible to enter either (1) a host domain name or (2) an IP
address in dotted-decimal (“#.#.#.#”) form. The host SHOULD check
the string syntactically for a dotted-decimal number before
looking it up in the Domain Name System.

DNSでルックアップできるのはドメイン名形式かIPアドレス形式になります。使える文字はRFC 952で定義されています。

<hname> ::= <name>*[“.”<name>]
<name> ::= <let>[*[<let-or-digit-or-hyphen>]<let-or-digit>]

RFC 1123で書かれている通り、最初の文字は英字だけではなく、英数字が使えるように後で仕様が若干緩和されています。

注:IPv6アドレスは別のRFCで定義されています。ここではIPv6は重要ではないので省略。

徳丸さんは私がIPアドレスと書いたので間違っているかのような書き方をしていましたが、RFCで明確にドメイン名形式またはIPアドレス形式と書いており、gethostbynameもこの仕様にそった実装になっているのでドメイン名形式とIPアドレス形式を明確に区別することにあまり意味はありません

 

ホスト名のバリデーションの仕方

バリデーションは仕様に則り行います。

ホスト名のバリデーションの方法はRFCの定義で明確です。RFC通りにバリデーションするだけでOKです。

  • ホスト名は最大255バイト
  • “.”で区切られたラベルは最小1、最大63バイト
  • ラベルに使える文字は英数字とハイフン

PHPなら以下のようなコードになります。

<?php
function validate_host_ipv4($host) {
  $len = strlen($host);
  if ($len > 255) {
    return FALSE;
  }
  if ($len !== strspn($host, 'abcdefghijklmnopqrstuvwxyzABCEDFGHIJKLMNOPQRSTUVWXYZ1234567890-.')) {
    return FALSE;
  }
  $labels = explode('.', $host);
  foreach($labels as $v) {
    $label_len = strlen($v);
    if (!$label_len || $label_len > 63) {
      return FALSE;
    }
  }
  return TRUE;
}

備考:さらに厳密にチェックする場合、ラベルの最後に”-“があってはなりません。

 

メールアドレスの確認

メールアドレスのホスト部分の最大長は255バイト、ユーザー名の部分は通常OSのファイル名の長さ(ディレクトリ名もファイル名の一種)で制限されます。

http://en.wikipedia.org/wiki/Comparison_of_file_systems

Reiser4のように長い物のありますが、凡そ255バイトが最大長と考えて良いです。”@”を足しても512バイトに制限してバリデーションしておけば大丈夫でしょう。

 

この入力バリデーションでGHOST攻撃を防げるのか?

gethostbynameに不正なIPアドレス形式が渡されたGHOST攻撃の場合、ワーキングバッファのアドレス計算ミスを利用しています。GHOSTでオーバーフローさせる為にはバッファサイズぎりぎりまで使い切らせた場合に4バイトまたは8バイトオーバーフローします。バッファサイズは1KBのようなので、上記のバリデーションであれば問題ありません。

ホスト名は最大255バイトまでなので、単純に長さのチェックをしているだけでも攻撃は防げました。

 

入力バリデーションはアプリケーションの仕様なのか?

入力バリデーションはセキュリティ仕様です。ISOやJISでもそのように記述されています。

セキュリティ仕様もアプリケーション仕様の一つです。随分前から国際標準規格として採用されていることを明らかにする為にISO 27000の前身であるISO 17799から紹介します。ISO 17799はJIS X 5080の国内規格としても採用されています。

10.2.1 入力データの妥当性確認
業務用システムに入力されるデータは、正確で適切であることを確実にするために、その妥当性を確認することが望ましい。業務取引処理(transaction)、常備データ(名前、住所、信用限度、顧客参照番号)およびパラメタ(売価、通貨交換レート、税率)の入力を、検査することが望ましい。次の管理策を考慮することが望ましい。
a) 次の誤りを検出するために二重入力又はその他の入力検査。
1) 範囲外の値
2) データフィールド中の無効文字
3) 入力漏れデータまたは不完全なデータ
4) データ量の上限及び下限からの超過
5) 認可されていない又は一貫しない制御データ
b) その妥当性及び完全性を確認するために重要なフィールド又はデータファイルの内容の定期的見直し
c) 入力データに認可されていない変更があるかとうかについての紙に印刷した入力文書の点検
d) 妥当性確認の誤りに対応する手順
e) 入力データのもっともらしさを試験する手順
f) データ入力過程に携わっているすべての要員の責任を明確に定めること

備考:ISO 17799のセクション10にはセキュアなプログラム開発に役立つ良い指針が記述されています。是非、一度読んでみてください。(ISO 17799は古いのでISO 27000を参照することを推奨)

ISO 17799の基となったBS 7799 (英国のJISのような規格)が銀行などの業務システムに対するセキュリティ対策として作られたので、このような記述になっていますがアプリケーション一般に適用できるセキュリティ対策です。

「あなたの作っているアプリケーションは業務システムではないので、国際セキュリティ標準規格に書いてあっても実装しなくても構いません」とセキュリティ専門家が顧客にアドバイスするのは問題です。「あなたの作っているアプリケーションは業務システムではないですが、国際セキュリティ標準規格に書いてあるように入力バリデーションの実装をお薦めします」とアドバイスすべきなのがセキュリティ専門家ではないでしょうか?

またBS 7799が想定していた「業務アプリケーション」を明確に区別することにも意味はあまりありません。Webサイトでサービスを提供している会社にとってはWebアプリも業務アプリケーションです。

話がそれましたが、Eximの場合「4) データ量の上限及び下限からの超過」を行っているだけでもGHOST脆弱性の攻撃を受けませんでした

徳丸さんは以前から入力バリデーションはセキュリティ対策ではなく、アプリケーションの仕様だとの主張をされています。

  • バリデーションの基準はアプリケーション仕様(再掲)

最初にリンクしたブログでもこのように書かれています。この主張はセキュリティ専門家として矛盾しています。そもそもセキュリティ対策は数えきれない仕様の中から「セキュリティに関連する仕様集」としてまとめた物です。

BS 7799の頃ならまだしもISO 17799は国際標準セキュリティ規格で、JIS規格でもあります。BS 7799は1995年、ISO 17799は2000年に制定されています。またISO 17799/27000は国際セキュリティ認証のISMSの基盤となっており、多数の企業が認証を取得しています。

IoT時代に開発者が先ずすべきセキュリティ対策は入力バリデーションです。国際標準規格に記述され、セキュリティ専門家も一番のセキュリティ対策とする入力バリデーションを行わなくても良いようなアプリケーション仕様である、とするのはセキュリティ専門家として問題ではないでしょうか?

セキュリティの概念についてもう少し知りたい方は標準と基本概念から学ぶ正しいセキュリティの基礎知識もどうぞ。

 

投稿者: yohgaki