memcachedの活用と運用 実践編

第2回 memcachedのセキュリティと脆弱性

この記事を読むのに必要な時間:およそ 3 分

memcached injection

memcachedにはmemcachedクライアントから不正なキャッシュ名を送信することで任意のコマンドを注入(injection)することが可能となる脆弱性があります。2008年にNTTコミュニケーションズ株式会社より,memcached Injectionについての資料が発表されています。

memcached Injectionについての資料(NTTコミュニケーションズ)
http://www.icto.jp/security_report/pdf/sr20080310.pdf

memcachedの主流なプロトコルはアスキープロトコルです。アスキープロトコルでは改行で区切られた平文のテキストをサーバとクライアントとでやりとりを行うことでキャッシュオブジェクトの保存取得を行います。このプロトコルの利点としてtelnetを使って簡単にmemcachedの操作することができるなど,人間から見たときのわかりやすさが挙げられます。しかし,命令文やキャッシュ名の途中に改行やスペースを入れることでプロトコルを騙す事ができ,Injectionの機会が生まれます。

キャッシュのキーに改行を入れることによるInjection

キー名に改行を入れることによるInjectionの例です。Perlのクライアントを想定しています。

$memd->get("foo\r\nset bar 0 0 4\r\ntest");

getコマンドでキャッシュオブジェクトを取得するソースコードですが,その際にキャッシュのキーに改行を含め,その次にsetコマンドとなる文字列を追加しています。上記のコードを実行したときのmemcachedサーバの様子を -vv オプションのログで確認します。

<30 new auto-negotiating client connection
30: Client using the ascii protocol
<30 get foo -----(1)
>30 END ----(2)
<30 set test 0 0 4 ----(3)
>30 STORED ----(4)
<30 connection closed.

(1)で本来のgetコマンドが発行されていますが,途中で改行が入っているため,(2)で命令が終了したのち,(3)でsetコマンドが実行され,(4)でsetが成功しキャッシュの保存ができていることが確認できます。

実際にsetなどのキャッシュの操作コマンドが発行されなくても,改行コードやスペースなど不正な文字列が入ることで意図する動作にならない可能性があります。このInjectionを防ぐにはキャッシュのキーに対してURI Escapeなどを行い,サニタイズしてからmemcachedクライアントに渡す対策が有効です。以下はPerlでの例です

use URI::Escape;
my $s_key = uri_escape( $key, "\x00-\x20\x7f-\xff");
$memd->get($s_key);

キャッシュのキーの長さによるInjection

改行コードなどの制御コードによるInjectionの他に,memcachedのプロトコル上決められている250文字より長いキーを使用するとInjectionを引き起こすことができます。

$memd->set("x"x251,"delete test");

上記のソースコードでは251文字のキーにて,deleteから始まるテキストを保存しようとしています。実際に動かして,サーバ側の動作をみると

<30 set xxxxx(…略…)xxxxx 0 0 20
>30 CLIENT_ERROR bad command line format ---(1)
<30 delete test ----(2)
>30 DELETED  ----(3)
<30 connection closed.

(1)で251文字のキーを受けたことでエラーを発生していますが,クライアント側はかまわずdelete命令が含まれる次の行を送信してしまっているため(2),(3)で削除が完了しています。このInjectionを防ぐにはキーの文字列の長さを確認するのが最も有効です。また一定以上の文字数のキーを自動的にhash値に置き換えてしまう手段もあります。

if ( length $key >= 240 ) {
$key = Digest::MD5::md5_hex($key);
}
$memd->set($key, "delete test");

上記の例では,240文字以上のキーを自動的に32文字のMD5のhash値に入れ替えます。キーが250文字より大きくなる心配はないので,setの第二引数に渡されたdeleteは実行されることはありせん。

改行コードや文字数オーバーによるInjectionは,JavaやPythonなど一部のクライアントライブラリでは対策がすでにされていますが,その他の言語のライブラリではキーの確認などを行っていないため,Injectionが起きる可能性があります。memcachedを利用したアプリケーションを開発運用している方は,Injectionが発生しないかを一度確認する必要があると思われます。

Injection対策としてバイナリプロトコルを使う

memcachedのinjectionはすべて,アスキープロトコルでの制約上生まれた脆弱性なので,バイナリプトコルを使い,アスキープロトコルを利用しなければ問題は起きにくくなります。アスキープロトコルを無効にするにはmemcachedの起動オプション -B を使います。

memcached -B binary

-B オプションでbinaryを指定することでバイナリプロトコル以外を受け付けなくなります。デフォルトはautoで,アスキープロトコルとバイナリプロトコルを自動判定します。

まとめ

今回はmemcachedを運用する上で確認が必要なセキュリティと脆弱性について書かせていただきました。memcachedはシンプルで非常に高速に動作しますが,認証機構やセキュリティといった側面では機能が不足していると思われるような部分があります。実際の運用ではここで紹介したような脆弱性対策についても気を配ることが求められます。次回は安定運用に欠かせないmemcachedの監視について紹介します。

著者プロフィール

長野雅広(ながの まさひろ)

株式会社ライブドア 開発部 システム管理グループ所属。最近はリソース監視ツール「CloudForecast」を開発しながら,ライドドアのさまざまなサービスに導入を行い,スケーラビリティの向上を目指している。

URLhttp://blog.nomadscafe.jp/

コメント

コメントの記入