Category Archives: Security

[IM] OAuth2あるいはOpenID対応

Google AppsのOAuth2対応について、Using OAuth 2.0 to Access Google APIsに説明されています。この認証方式をサポートしました。したがって、OAuth2対応およびOpenID対応と言えるかと思います。Google以外のプロバイダについては今後、確認します。まずは、認証できるようになっているので、その使用方法を説明します。

OAuth認証するクライアント

まず最初に、ページをOAuth対応にした場合にどんな感じにページ表示されるのかを示します。認証を必須にすると、INTER-Mediator内蔵のログインパネルが表示されそこに「OAuth認証」というボタンが登場します。ここで、ボタンをクリックします。

shot2712

初めて利用するときには、次のように、認証アカウントから何を取り出すのかを表示するメッセージが出てきます。ここで「許可」をクリックします。なお、複数のアカウントでログインしている場合には、さらにどのアカウントでログインするのかを問い合わせるページもこの前に表示されます。

shot2713

そして、認証されます。おなじみのサンプルのページです。ログインユーザーは、ここでは意図的にプロバイダーによって提供される一意な名前とプロバイダー名を@でつないであります。

shot2714

認証のデータベースを見てみると、そちらに新たにユーザーが追加されています。つまり、外部にあるユーザーの認証ではありますが、いったん、利用しているデータベースのauthuserテーブルに、ユーザーを作り、もっぱらauthuserテーブルのユーザー情報を利用して、認証を行います。一定時間で無効化しますが(今日現在未実装)、それまでは、OAuth認証直後にランダムに生成したパスワードをクライアントに通知して記憶させ、INTER-Mediator自身の認証処理を行うことで、都度都度OAuthサーバーとのやりとりはないようにします。

shot2715

Googleでのアカウント発行

GoogleのOAuth2を利用するためには、アカウント発行が必要です。このアカウントは、アプリケーション、つまり、INTER-Mediatorで作るページに対するアカウントです。ページの利用者はこれらの情報は不要ですし、見えるようにする必要はありません。

まず、Googleデベロッパーのコンソールページに移動します。ここで、「プロジェクトを作成」をクリックします。このページは、もしかすると、2つ先のような画面になっているかもしれません。その場合はページの中にある新規プロジェクトを作成するようなボックスがあるので、それをクリックします。

shot2701

プロジェクトの作成で指定するのはプロジェクト名のみです。もちろん、開発者が把握できる名前を指定して、「作成」ボタンをクリックします。

shot2702

このようなページになります。追加したプロジェクトが1つのボックスになっています。また、左側に見えるように、このページが「ホーム」です。初めての利用であれば、このページに行きますが、以前い何か利用していた場合ではこの限りではありませんので、臨機応変に対処しましょう。ここまでで、ともかく1つのプロジェクトを作成してください。

shot2703

プロジェクトのボックスの右下にある「V」マーク部分をクリックすれば、内容が開きます。ここで、「プロジェクトの詳細」をクリックします。

shot2704

左側のナビゲーションで、APIと認証にある、「認証情報」をクリックします。認証情報というパネルが出るので、「認証情報を追加」をクリックします。

shot2705

ドロップダウンから、「OAuth 2.0クライアントID」を選択します。

shot2706

このような画面になります。「同意画面を設定」をクリックします。ここの同意画面は、最初に認証するときに見える画面です。

shot2707

メールアドレスはGoogleアカウントのメールアドレスが設定されています。サービス名を適当に記述しますが、この名前がタイトルになります。その他は「省略可」であるので、認証の動作には影響しません。入力をして「保存」ボタンをクリックします。

shot2708

アプリケーションの種類は「ウェブアプリケーション」を選択します。そして、「名前」は一覧の中で識別する名前を適当に指定します。そして、承認済みのJavaScript生成元には入力せず、承認済みのリダイレクトURLに、ここではINTER-Mediatorに含まれている/Auth_Support/OAuthCatcher.phpのURLが示されています。実際に利用するときには、このファイルのコピーを作るなどしてもかまいませんが、このまま利用してもかまいません。ログインパネルの「OAuth認証」ボタンをクリックすると、Googleが指定する「トークンリクエスト」のURLに移動し、ユーザーの特定や取得可能な情報のアクセス許可をページ上で求めます。その後に、「承認済みのリダイレクトURL」にリダイレクトするときに、アクセストークンが引数として渡され、INTER-Mediatorはそれを元に、OAuthユーザーをデータベースに作成します。

shot2709

「作成」ボタンを押すと、クライアントIDとクライアントシークレットが表示されます。これらはparams.phpファイルにコピペをします。コピペの方法は後で説明します。(ご安心ください。このIDとシークレットはすでに無効化してあります)

shot2710

OKをクリックすると、発行したアイアウントが一覧されるページになります。ここから、削除や追加、あるいは変更などのアカウントの管理もでき明日し、同意画面の変更などもできます。

shot2711

INTER-Mediatorで作成するファイル

OAuth認証を使いたいページでは、まず、定義ファイルに基本的な設定を行います。例えば、以下のファイルは、Samples/Sample_Auth/MySQL_definitions.phpの記述です。IM_Entryの第2引数に、authenticationキーで連想配列を指定します。とりあえず、クレデンシャルの記録方法(ここではセッションストレージ)とレルム(ここでは「Sample_Auth/MySQL_definitions」)を指定します。レルムは単に同一認証を受け付ける領域名とと考えてください。

IM_Entry(
    array( /* コンテキスト定義 */
    array(
        'authentication' => array(
            'storing' => 'session-storage',
            'realm' => 'Sample_Auth/MySQL_definitions',
        ),
    ),
    array('db-class' => 'PDO'),
    2
);

Googleに関連づける情報は、params.phpファイル側に記述できます。これらは、定義ファイルでは記述できないのが現在の仕様です。それぞれ、以下のように、決められた変数名に値を指定します。最初はプロバイダーで現在は「Google」のみサポートしています。続いて、クライアントIDトクライアントシークレットを、Googleのデベロッパーコンソールのページからコピー&ペーストします。最後のリダイレクトのURLは、「承認済みのリダイレクトURL」と同じURLを指定します。

$oAuthProvider = "Google";
$oAuthClientID = '1084721348801-jv3hvi4shcmr4j7unuhioq8k2mm47n6s.apps.googleusercontent.com';
$oAuthClientSecret = 'hV5TZD8x108K1Zac4RfZopur';
$oAuthRedirect = 'http://localhost:7001/Auth_Support/OAuthCatcher.php';

まだ完成というまでには至っていませんが、ともかく、認証できるところまでを作りました。タイムアウトのタイミングや、カスタマイズポイントなどを作りこみたいと思いますが、ご意見があれば、Facebookのグループでよろしくお願いします。

[IM]LDAP認証の実装がだいたいできてきました

INTER-Mediatorには、自分自身でユーザーテーブルを持つ認証(ビルトイン認証)が可能です。そして、データベースエンジンのユーザーによる認証(ネイティブ認証)もすでにサポートしています。次に取り組むのはやはりLDAPです。ただ、MySQLにはLDAP接続のプラグインがあり、そういう手法を使えば、ネイティブ認証の一環としてLDAP認証を実現することができます。しかし、通常とは異なるデータベース運用が必要になりますし、MySQLとPostgreSQLで動作に違いがあるとまた大変です。SQLiteはそういう統合はできません。LDAPについては、単に認証の確認だけだと、要するに認証バインドをするだけのことであり、PHPではさほど難しくはないので、データベースエンジンと独立してLDAP認証の仕組みを搭載しました。

LDAPサーバに対する設定

まず、LDAPサーバ情報は、params.phpファイルに、変数で記載する方法にしました。LDAPでの認証時は、ユーザーはユーザー名だけを与えるのではなく、ユーザーレコードのDN(Distinguished Name)を指定する必要があります。たとえば、OS X Serverで、ホスト名がhomeserver.msyk.netの場合、

uid=msyk,cn=users,dc=homeserver,dc=msyk,dc=net

というのがユーザーを特定するDNとなります。ここで、dc…以降は「検索ベース」、cn=usersは「コンテナ」とします。さらに、OS X Serverはuidという属性名でユーザー名を指定しますが、これもActive Directoryでは違うこともあって、結果的に上記のユーザー名「msyk」以外の部分をすべて、変数で与えて、DNを構成するようにしています。サーバーのURL、ポート番号も合わせて、結局、params.phpファイルに以下のように記載をすることにします。

$ldapServer = "ldap://homeserver.msyk.net";
$ldapPort = 389;
$ldapBase = "dc=homeserver,dc=msyk,dc=net";
$ldapContainer = "cn=users";
$ldapAccountKey = "uid";

なお、$ldapServer変数に設定されている文字列の長さが0以上なら、LDAP認証を試みるように動作します。これらの変数部分を全部コメントにすると、LDAP認証に関しては何も行わず、以前の通りの動作になるようにしました。

PHPのLDAPライブラリの機能を使って認証するとしたら、その認証のためのバインドはサーバーからLDAPサーバーに送られます。ということは、クライアントからサーバーに対して、ユーザー名とパスワードを送り届けないといけません。これは、ネイティブ認証の仕組みを利用しますが、そのために、鍵ペアを生成して、params.phpファイルに記述します。以下の部分です。もちろん、最初から入っている鍵ではなく、コメントに書いている方法で自分が使用する鍵に置き換えてください。もちろん、クライアントに送られるのは、公開鍵です。

$generatedPrivateKey = <<<EOL
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBAKihibtt92M6A/z49CqNcWugBd3sPrW3HF8TtKANZd1EWQ/agZ65
 :
jU6zr1wG9awuXj8j5x37eFXnfD/p92GpteyHuIDpog==
-----END RSA PRIVATE KEY-----
EOL;

ネイティブ認証との混合動作

そして、LDAPアカウントでのログインは簡単にできました。ただし、1回の認証バインドに0.2〜0.3秒ほどかかります。同一のサブネットです。たとえば、フォームのサンプルだと、1ページの合成にデータベースアクセスを15回ほど行うので、5秒くらいのアクセス時間の増加になります。これは、ちょっと長いです。また、単に認証ができたとしても、グループ設定との連動等といった問題があります。

そこで、LDAPアカウントで認証が成功したら、ビルトイン認証で使うテーブル(authuserテーブル)に、そのLDAPのアカウントの情報をレコードとして追加することにしました。1回成功したら、ビルトイン認証テーブルにユーザーを追加し、パスワードもわかっているのでハッシュ化したパスワードを保存します。そのために、ビルトイン認証を行って失敗するとLDAP認証を行うという流れにしました。ビルトイン認証とLDAP認証は切り替えるのではなく、この順序で両方行います。
しかし、その追加したユーザーがいつまでも使えるのは問題で、タイムアウトさせないといけません。そこで、結果的にはビルトイン認証のテーブルにDateTime型のフィールド「limitdt」を追加する必要が発生しました。現在の実装では、そのフィールドの有無で落ちることはないようにしてありますが、LDAPを使う場合には追加したフィールドの定義がされていないといけません。

こうしてユーザーのレコードを作っておくと、グループへの登録ができます。ユーザー名で識別され、1度登録すると消されないので、主キー値は保持されるはずです。タイムアウトすると、LDAP認証を試みます。ただ、この部分、現在実装中で、うまくいったりいかなかったり、一進一退ですが、ある程度のところまで動くようになっています。ちなみに、MoodleもLDAP認証をサポートしますが、ログインを1度することで、ユーーザーレコードが作られる仕組みになっており、やはり同じような仕組みをINTER-Mediatorでも実装しています。

認証処理の流れ

初めて、LDAPアカウントでログインしようとするとき、ビルドイン認証のテーブルにはそのユーザーはありません。したがって、ビルトイン認証では失敗しますが、その後のLDAP認証で成功します。このとき、新たにビルトイン認証のテーブルに、そのユーザーのレコードを作りパスワードのハッシュと期限を記録します。クライアント側には認証のための情報が残されているので、この次の通信時からは、自動的にビルトイン認証が成功します。したがって、1画面作るのに20回の通信処理が必要でも、最初の1回だけがLDAP認証されます。

次の通信処理が、LDAP認証のタイムアウト以内の期間なら、ビルトイン認証が成功して終了します。そのとき、limitdtフィールドも現在の時刻に更新します。しばらくクライアントを利用しないなどでタイムアウトになると、ビルトイン認証は失敗しますが、引き続くLDAP認証が成功するように、クライアントでは、LDAP認証とネイティブ認証に必要な情報が残されています。そして、1度LDAP認証に成功すると、次回以降はまたネイティブ認証がタイムアウトまで成功します。

認証に必要な情報はクッキーに保存することもできるので、翌日にまた認証を継続させることもできます。

今現在、動作が怪しいのは、LDAP認証のパスワードを変えたときです。まず、この方法だと、LDAP認証のタイムアウトの時間が来るまでLDAPでの認証は行われないので、その期間は変更前のパスワードが通ります。これは、とりあえず、仕方ないことの1つとしておきます。そして、タイムアウトしてLDAP認証すると、当然ながら以前のパスワードでは認証が通らないので認証エラーとなり、ログインパネルが表示されます。ここで、新しくなったパスワードを入力すると、また同じように動作するというのが期待する動作です。このあたりの挙動が現状、今ひとつな感じです。

FileMakerはサポートせず

なお、LDAP認証は、PDOのみで、FileMaker Serverはサポートしません。どうしようかと思ったのですが、Admin Consoleでの設定で「外部サーバーアカウント」をクライアント認証で使えるようにしておけば、ネイティブ認証で事実上、Active Directory、Open Directoryは利用できます。LinuxのLDAPは使えないけど、FileMakerのクライアントで使えないで、Web側だけで使える仕組みまでのサポートは必要かどうか疑問ですので、FileMakerはINTER-Mediator組み込みのLDAP認証はサポートしないということにしたいと思います。

第三者を介在せずに「抽選」を行う方法

Facebookに記事を書いたように、機材の販売先を決める抽選が必要になりそうです。第三者に立ち会ってもらって公正にするということは可能でしょうけど、それでも不正の確率は0になりません。頼まれた方もいい迷惑(笑)。なんかいい方法がないか考えました。こんなのはどうでしょう。

基本的な手法

  1. 当せん決定者は、何か1文字を思い浮かべるが、公表しない
  2. 複数の抽選参加者は、何か1文字を思い浮かべて公表する
  3. Unicode のエンコードで、決定者の文字に一番近い参加者が当せんとする

しかし、いろいろ問題があります。決定者が、参加者の公表よりも後になって、思い浮かべた文字を変えてしまうということをしても検出する方法がありません。つまり、決定者は、誰かが当せんするように、意図的に文字を思い浮かべ、それを事前に思い浮かべたものとしてしてしまうと不正が成立します。

では、決定者が文字を思い浮かべた時点で、第三者に伝達する方法があります。しかし、これは決定者と第三者、あるいは参加者と第三者が、裏で結託していると、やはり不正が成立します。

不正を防止する手段

しかしながら、以下のような、ダイジェスト(あるいはハッシュ)を利用する方法をすれば、第三者の介在なしに、不正ができないと考えますがどうでしょう。

  1. 当せん決定者は何か1文字を思い浮かべる:その文字をcとする
  2. 当せん決定者は、別の適当な文言を思い浮かべる。何文字かは公表しない:文章をsとする
  3. s+cのダイジェストd1を求めて公表する
  4. sのダイジェストd2を求めて公表する

こうして2つのダイジェストを求めますが、当然ながら、決定者はファイル等で、sとcを残しておきます。これらのファイルや文字列が、最終決定までに漏えいしないことが前提です。

2つのダイジェストを公表したのちに、参加者は、期限までに「自分が思い浮かべた1文字」を公表します。他人の表明を見ての変更もありとしてもいいかと思います。

最初cのダイジェストを求めればいいかと思ったのですが、Unicodeで1文字程度なら、全部チェックで比較的短時間でわかってしまうという懸念があります。もちろん、公表から10分以内という手もありますが、セキュリティホールの確率が下がるだけです。そこで、不定長の文字列と組み合わせることを考えつきました。

データの作成例

以下は、具体例です。sha1は、「openssl sha1 (ファイル名)」で得られます。公開/非公開は、参加者の表明が終わるまでの間の扱いです。

s="サンプルテキストです:"(非公開)
c="A"(非公開)
sのsha1→34591a094e22f43fb1ba99426265383993599c96(公開)
s+cのsha1→1c19e4ce3a0d49b6dff756e2bf62bdd605355051(公開)

ここで、公表するのはsha1のダイジェスト値のみです。従って、この2つのバイナリデータから、「A」を推測するのは難しいです。cのダイジェストならば数万回程度の試行で元の文字列が分かるかもしれないけど、上記のd1とd2は「不定数の文字列のダイジェスト」なので、ブルートフォース攻撃の必要アタック数は桁違いに高くなります。決定者がAないしはsを変えてしまって、同一のダイジェスト値を得るのは、ほぼ無理と考えれば、不正が入る余地はありません。もちろん、sha1ではなく、sha512などを本番では使うべきでしょうね。

sもcも決定前には未公開なので、参加者は偶然に当ててしまった場合でも、当たったかどうかは分からないはずです。

なお、抽選者が3人以上の場合、「文字コード上で一定以上の距離を空ける」というルールは必要でしょうね。例えば、ある人が「F」と言ったとします。別の2人が「E」と「G」と宣言して、最初の人の当せん確率を限りなく0にすることが可能です。つまり、別の2人が結託している状況です。まあ、これは監視されている上なので、普通はやらないとは思いますが、厳密にはそのルールが必要かと思います。

抽選者にとって、確率は同一になるかどうか? ここはアイデアが固まっていません。抽選者にとってはcは未知なので、Unicodeのコード空間上、どこにあるかは分からないという点では均一なのかもしれません。しかし、cが空間の端の場合とど真ん中の場合で抽選者に影響はあるのかどうかという点も気になります。cを複数設定して、参加者の1文字は一番近いcを採用するといったようなランダム化は必要なのかもしれません。しかし、この問題は、ちょっと難しそうなので、cは1つということにします。

いかがでしょうか?

[IM]MediaAccessクラスと新たな拡張点(2)

こちらの文書の続きです。

FileMakerのオブジェクトフィールドを参照する

オブジェクトフィールドはデータベースごとに扱いが異なり、統一的にはやりにくい処理ではあります。MediaAccessクラスでは、FileMaker Serverをターゲットにオブジェクトフィールドに対応する機能を作成しました。

FIleMakerはFXを経由し、XML共有の仕組みを使います。テキスト型や数値型は、基本的にテキストでフィールドにあるデータが得られます。一方、オブジェクトフィールドはオブジェクトそのもののデータではなく、フィールドのデータに応じた以下のような「テキスト」が得られます。

/fmi/xml/cnt/photo.jpg
http://server:16000/…

PDFは完全なURLで、FileMaker Serverに16000ポートで接続して取り出すことが可能です。JPEGなどの画像の場合は、URLのパスに相当するものが得られますが、たとえばIMGタグのSRC属性にそのまま指定が可能な文字列になります。

いずれにしても、両方ともURLであると解釈すればいいわけです。この仕組みはFileMaker Serverに限らず、一般的なアクセスにも使えます。つまり、media=URLと指定をした場合は、そのURLにアクセスしたデータをMediaAccessクラスが取得し、さらにクラスを呼び出した元にそのデータを返します。/fmi/xml/cntで始まる物だけは特別にURLであるという処理が組み込まれています。また、URLかどうかはそれ以外には、httpあるいはhttpsで開始するものかどうかで判定しています。

MediaAccessでのアクセス権

認証が成立したらすべて参照可能となり、成立しなければ参照不可という単純なものなら非常に話が早く、前に説明したmedia-tokenの仕組みで事は足りるのです。なお、データはCRUDの4つの側面がありますが、メディアに関しては「編集」というのはWeb世界ではかなり難易度が高い世界であり、MediaAccessクラスはほぼ参照のみのサポートになっています。

ここで、メディアそのものがログインしたユーザごとのアクセス権を持たせたい場合が出てきます。レコードについては、特定のフィールドにユーザ名やグループ名を入力することで、そのユーザやグループに所属したユーザでないと参照や更新ができない仕組みを持っています。フィールドのデータはそれでいいのですが、メディアは実体はレコードと別に有ります。ここで、個々のメディアをコンテキストのレコードと結合させ、レコードごとのアクセス権をメディアにまで及ぼす仕組みを組み込みました。

まず、IM_Entry関数の2つ目の引数(オプション引数)に、キーが’media-context’で値がコンテキスト名(コンテキストのnameキーに対する値)を与えます。すると、メディアはこのコンテキストにある特定のレコードの、1つのフィールドのようなふるまいになります。

‘media-context’ => ‘context-name’,

実際にメディアにアクセスするパスは次のような形式にします。つまり、コンテキスト名、レコードの検索条件をパスに入れます。最初のfilesは特に意味はなく、相対パスの最初のキーワードです。context-nameは、media-contextの値と同じでなければなりません。そのコンテキストのkeyキーに対する値、つまり主キーがpidであるなら、たとえば、field=valueは、pid=312 のような値になります。

context.php?media=files/context-name/field=value/filename.png

ここでもし、media-root-dirが /var/www/media であるなら、実際に

/var/www/media/files/context-name/pid=312/finename.png

という絶対パスの画像ファイルが存在する必要があります。コンテキストの定義には、レコード単位のアクセス権設定があれば、メディアに対するアクセス権の認証の確認を行い、ユーザを特定します。pid=312のレコードがそのユーザにアクセス権があるのかどうかを確認することによって、アクセスの可否を決めます。従って、適当にpid=316などとパスを変えても、その条件で検索されたレコードが他のユーザに対する権利があるものであれば、400番台のレスポンスを返してデータは返しません。認証の確認を行い、そのユーザに対するアクセス権がないものは出力しないという仕様によりアクセス権は定義した通りに適用されます。

pid=312を、age=45のようにできると言えばできますが、おそらく、そういうディレクトリは存在せず、漏洩にはならないでしょう。

ファイルのアップロードのコンポーネントは、コンテキスト名やレコード検索条件のパスを自動的に作成するようにも作られています。

とまあ、ここまで書いたところで、ソースに間違いを発見! また、グループ名をフィールドに入れる場合はまだ実装していなかったことも思い出しました。今のところ、メディア関連処理は、開発している側で「必要の合った」状況しかうまく動かない可能性があります。ぜひとも、いろいろ試してフィードバックをください。

(まだ続く)

Booking.comを騙るメール

来ました。予約した覚えはないのですが、1泊で1800ドルとはゴージャスなものです。ただ、よくあるタイプの別のサイトへの誘導は明示的ではなく、HTML内にあるのリンクはちゃんとbooking.comに行きますね。しかし、金額は書いてあるけど、どこのホテルか書いていない。そんな予約はありえないでしょう。このメールアドレスで昔booking.comを使った可能性もあるのですが、なんとアカウントは作られていませんでした。まあ、これでほとんど安心なのですが、念のためアカウントを作ってみたのだけどやはり予約は入っていません。また、添付するzipを展開するとexeが入っていたので間違いなく、嘘メールでしょう。あと、巧妙なのは、本物のBooking.comの広告メールと同じような時間に配布しているところですね。

だけど、ClamXavだとマルウェアと判定はしませんでした。Booking.comには似たような警告はありますが、このメールではなく、1年ほど前の別のもののようです。ということで、警告の意味も含めてブログに記載します。1ヶ月ぶりの書き込みがこんな話題ですんません。

スクリーンショット 2013-08-06 14.52.52 スクリーンショット 2013-08-06 14.53.09

DHCPセキュリティ弱い説:続編

先日、このブログに、「DHCPはセキュリティが低い!?」を書いたところ、けっこう反応がありました。現状、「セキュリティが弱い」というコンセンサスがないにもかかわらず、固定IPで運用しているという場面は決してない訳ではないということで、Twitterでもレスポンスをいただきました。

しかし、そんな情報がどこから出て来たのだろうかとふと疑問に思い、いろいろ検索をしてみました。まずは、マイクロソフトの「DHCPのセキュリティ情報」です。最初に『DHCP と関連プロトコルでは、次のようなセキュリティ上の問題が判明しています。』と前置きをして、以下のようなことが記載されています。タイトルだけ抜粋します。

  1. DHCP が認証されていないプロトコルです。
  2. DNS サーバーに対するサービス拒否攻撃を、DHCP サーバーを介して実行できます。
  3. 承認されていない Microsoft 以外の DHCP サーバーが DHCP クライアントに IP アドレスをリースできます。

1の認証を経ないプロトコルであるというのはその通りです。ただし、認証を行う方法はあります。これは後で説明をします。2については、一般的なDHCPの問題ではなく、ホスト名とIPアドレスの対応をActive Directoryにレコードとして追加するダイナミックDNS特有のセキュリティ問題です。一般のDHCPには関係ありません。3についてはADに承認したDHCPという仕組みを利用できますが、当然ながらADとは関係ないDHCPを立てる事は可能なのです。文章を読むと、別に誤解をさせることは何も書いていません。しかしながら、前置きのところだけを見て、それだけで判断してしまう人もいるんじゃないでしょうか。

日本の学会誌についても、検索してみました。たとえば、「IPアドレス自動割り当て方式(DHCP)におけるセキュリティの実現方法」網淳子, 岡本利夫(1995年電子情報通信学会総合大会 B-829)という論文があります。この論文は、認証なしにIPアドレス配給ができるDHCPのニセモノサーバの存在を検知する方法を提案しています。その部分を引用すると『ところが、現状のDHCPはセキュリティの面で不充分であり、権限のないサーバーが勝手に立ち上がって誤ったアドレスや経路の情報を流したり、悪いホストが他のホストになりすまして情報の横取りをする可能性が高い。』となっています。省略すると「DHCPはセキュリティ面で十分じゃない」となるかもしれませんが、この論文はニセサーバの問題を論じているのです。固定IPで運用するべきとはどこにも書いていません。

他に見つかったのは「特集 モバイルコンピューティングを支えるシステム技術/移動透過な通信を実現するプロトコル(寺岡文男)」(電子情報通信学会誌 Vol.80 No.4 pp.344-349)というものがあり、ABSTRACTの引用をすると『DHCPはネットワークパラメータの自動設定を行うプロトコルである。Windowsにも実装されて広く利用されているが、認証の機構がなく、セキュリティに問題がある。』と書かれています。この記事では場所を移動する状況での通信方式についてのことが書かれていますが、DHCPのセキュリティについて論じたものではありません。認証をしないという仕組みについての喚起として記載されています。

いずれも間違えたことはもちろん書いていません。しかしながら、断片的に読んで結論を出してしまう人にかかれば、「DHCPはセキュリティ的に問題がある」ということになってしまいます。

ちなみに、現在において、DHCPの認証はできるかどうかというと、「簡単に」できます。1つはDHCPサーバに応答してもいいホストのMACアドレスを登録する方法です。ワイヤレスでも使われる場合もあります。使うPCのMACアドレスを逐一設定しないといけないので、管理の手間はかかりますが、確実な方法として使われています。ただ、MACアドレスの登録なんてどうやるの?と思う方もいらっしゃるでしょうけど、現在はいちばん安物のブロードバンドルータでも、管理ページを開けばこの設定は出てくるのじゃないでしょうか。サーバOSでのDHCPでは設定できて当然です。この機能が使えないという状況は、実際には皆無に等しいでしょう。

さらにより確実な方法として、802.1Xという手法があります。ただし、認証のためのサーバの設置や、場合によってはデジタル証明書の発行などの作業が必要になり、簡単には行きません。しかしながら、高いレベルのセキュリティを使うところでは利用されているソリューションです。

では、認証をしないDHCPで、どんな工夫があるのかも紹介しましょう。会社などでは、カードキーで社員証にもなっているカードをリーダに読み込ませないと、オフィスに入れない環境ならば、「オフィスにいるのは社員あるいは承認された人である」という理屈が成り立ちます。それがほぼ100%実現されるのであれば、認証をしないDHCPでも問題はないでしょう。

カードキーがないようなところでも、前に書いたように、普通は基本的なセキュリティ、つまりよそ者が簡単には入れないようになっているので、概ね問題ないと考えるのが一般的です。よそ者がネットに簡単につなげるようなところでは、ネットワーク以前に財布や家具がなくなります。また、検索して見つけた記事で「我が家のインターネットはDHCPではセキュリティ的にまずいでしょうか」という答えに「ネットの心配をする前にまずは鍵を直しましょう」という回答がありましたが、まさにその通りですね。

DHCP危険説は一種の都市伝説かもしれません。もちろん、プロトコル的な問題点はあるのですが、これまでにも説明してきたように、それらの問題点は実際には問題にはなっていませんし、認証をさせるという解決策もあります。おかしな伝説がまことしやかに流れることがないように願う次第です。

DHCPはセキュリティが低い!?

このところ、「うちは固定IPです」というのをよく聞きます。ネットワークの設定を業者に依頼したときに、「DHCPはセキュリティ的に問題があるから固定IPにしましょう」と言われるそうです。もちろん、買ってきたマシンのセットアップが面倒ということもありますが、ところによっては、パソコンが増えるたびにIPアドレスを業者に指定してもらって設定しているとか。どうも、それでメンテナンス料を取っているのじゃないかと思われる節があります。

いくつかのサイトを見たところ、DHCPが脆弱であるという理由は、次の通りです。

  • どんな機材にでもIPアドレス等インターネット接続に必要な情報を渡すため、誰でも接続できる。
  • 不正アクセス時に誰がアクセスしたか分からない。

前者は、「悪意を持った人が簡単に接続できる」みたいな書き方をしていれば、まあ、みなさん、恐れるのは無理も無いかもしれませんが、よく考えると、この理屈には問題があります。

一般に、ネットワークと言えば、ワイヤレスないしはEthernetでしょう。ワイヤレスは接続自体にパスワードをかけるのが現状では一般化しているので、「社内の人しか使えない」みたいに言えなくはありません。まあ、そこも突っ込みどころありますが、ここではEthernetにフォーカスしましょう。

仮に、ある事務所で、EthernetでDHCPを使っていたとします。そうすると、もちろん、事務所外の人がそこにPCを持ち込み接続すると、インターネット接続できます。DHCPの問題点はそこだというわけですね。これは、Microsoftの技術文書にも書いてあります。

もちろん、MACアドレス(Ethernet ID)をDHCPサーバに登録するという方法で、外部の人の接続は阻止できますし、Active Directoryは確かにDHCPやDNSとの連動で阻害はできるので、いわゆる普通のDHCPより安全であることは言えるでしょう。では、一般的なDHCPが安全ではないと決めつける事ができるのでしょうか?

一般の事務所で、部外者が勝手に入ってきて、Ethernetにつなぐという行為があったとき、事務所の人は無視をしますか? 普通、どなたですか? ご用事はなんでしょうか? くらい聞きますよね。人の出入りが激しく部外者がいつでも出入りしている…というところがあったとしても、それは、Ethernetを設置するのが間違いで、普通はワイヤレスだけにします。部外者がEthernetを勝手に使えるような事務所があったとしたら、きっと、普通の悪者は「インターネットにつなごう」と思う前に、「財布を盗もう」とか「家具をぱくってやれ」くらい考えるでしょう。知らない人が入ってきて、勝手にお茶をわかそうとしたら、普通は排除しますよね。それと同じで一般には事務所のEthernetは人の目で監視されているはずです。そうではないとしたら、ネットワークのセキュリティ以前の問題です。

しかし、それでも、例えば、深夜に忍び込んでアクセスできるということもあるかもしれません。ネットワークを勝手に使ってデメリットはあるでしょうか? 勝手にファイルサーバの中身を盗まれたり、消されたりするという心配もあるでしょう。しかしながら、これは「すべてのサーバはユーザ名とパスワードの入力が必要」としておくことで、防ぐことができます。面倒臭いからと言って、誰でも読み書きできるファイルサーバを立てていれば、もちろん危険ですが、そういうサーバ管理はDHCP以前の問題で、そういう運用自体が危険です。重要な情報はともかく認証が必要としておけば、何も心配することはありませんし、不正アクセス自体をほぼ100%排除できるわけです。排除できれば、誰がやったのかを調べる必要はありません。これはDHCP以前に、ネットワークのセキュリティを確保するために必要なことです。

そうしたら、深夜に忍び込んだ悪者は、単にインターネットでGoogle検索するくらいしかやることはありません。月額固定の通信料だとしたら、ほとんど被害はないでしょう。だいたい、それ以前に、椅子とかロッカーとか盗まれますね。

さらにさらに、固定IPにすれば、インターネット接続できないと思っている人も居るかもしれませんが、固定IPのネットワークにつないで、ある程度ルータやDNSのアドレスに目星をつける事もできます。Mac OS Xだと、とりあえず可能なようです。やり方は、「ping 10.255.255.255」「ping 192.168.255.255」といった末尾が255のグローバルPINGでいろんなネットワークアドレスを試します。その後に「arp -a」とすれば、だいたい、応答があったホストのIPは分かります。後は、経験と勘でどれがルータか分かりますし、DNSサーバのホストもポートスキャンで分かります。不正アクセスしようという輩は、この手の手法はよくご存知でしょうから、「固定IPにしたら、インターネット接続できない」ということ自体間違いです。

思うに、こういう「DHCPはだめ」というのは、後々のメンテナンス費用で稼ごうとしている業者の作戦なのではないかと考えます。DHCPでちゃんと動けば、後は何もしなくてもOKとなると、メンテナンス費用をかせげません。IPをつどつど業者からアサインしてもらう上では、確かに業務としては発生しますが、なんだか、倫理的にぎりぎり、あるいは一線を超えてないでしょうか。

そういうわけで、DHCPは便利ですから、DHCPを使いましょう。言い換えれば、DHCPを取り入れたネットワーク管理ができるようになりましょう。家庭で当たり前のように使われているDHCPですが、事務所で使えないことにもっと疑問を持つべきです。

それでも、不安と思う方は、次のように考えてみてください。固定IPにしたときの設定の手間やIPアドレスの管理といった仕事が増えるコストは、DHCPにすることによるその損失(仮にあるとすれば)より、高くなっていませんか? 典型的な、セキュリティにかける費用が損失を上回る失敗プランなのです。いわば、保険金の払い過ぎってイメージでしょうか。