IncapsulaのRedisセキュリティレポートに関する補足
原文は Salvatore Sanfilippo により に公開されました。 このブログを購読する
数日前、朝起きてTwitterのタイムラインを見ると、「Redisサーバーの75%がマルウェアに感染」といった記事であふれていた。明らかに誤った引用で、元になっているのはIncapsulaの調査だ。そこでは、インターネット上に無防備なまま、保護もなく公開IPアドレスで開放されているRedisインスタンスのうち75%が感染していることが判明したというものだった[1]。
[1] https://www.incapsula.com/blog/report-75-of-open-redis-servers-are-infected.html
コンピュータセキュリティやRedisの仕組みについてある程度理解があれば、この話を文脈の中で捉えることは難しくないので、多くの人にとってこの件に関する補足は不要だろう。しかし、このブログ記事を書くのには二つ理由がある。一つは明白で、セキュリティやRedisにあまり詳しくない報道関係者やユーザーが、何が起きているのかを理解する助けになればということだ。もう一つは、外部に晒されたRedisインスタンスという事例が、「安全なデフォルト設定」について、セキュリティ界隈にとっても興味深いケーススタディになるからだ。
Incapsulaのレポート
まずはIncapsulaのレポートから見ていこう。彼らがやったのは、インターネット上に晒されているRedisインスタンスを分析することだった。公開IPアドレスで接続を待ち受け、パスワードによる保護もなく、インターネット上のどこからでも誰でもアクセスできてしまうインスタンスだ。HTTPサーバーのようなものだと考えればわかりやすいが、違うのは中身がRedisだという点で、Redisはそもそも外部に晒したまま運用するようには設計されていない。
これは決して新しい話ではない。Redisは非常に人気があるため、インストール総数は膨大で、そのうち一定の割合が晒されたままになっている。基本的に最初からずっとそうだった。クラウドプロバイダーで仮想マシンを立ち上げ、Redisをインストールし、アクセスできないことに気づいてVMのポートを誰でもアクセスできるように開放する。そうなれば、そのインスタンスは無防備な状態で動き続けることになる。変わったことと言えば、以前はそうしたインスタンスの多くが、クラックされずにそのまま動き続けていたという点だ。せいぜいスクリプトキディが接続して「INFO」コマンドなどを叩いて中身を覗く程度で、ほとんどの場合はそれで終わりだった。しかし今は、暗号通貨マイニングという新たな誘惑が、攻撃者に他人のシステムへ侵入する非常に強力な動機を与えている。いや、最高の動機だ。金になるからだ。そうして同じように晒されたインスタンスが、今度はなんらかの暗号通貨をマイニングするソフトウェアをインストールするためにクラックされている。Incapsulaは、侵害されているように見えるインスタンスの割合を調査したのだ。
彼らがRedisインスタンスに対する攻撃手法を収集した方法は、意図的に晒されたインスタンスを複数用意し、攻撃者がどのように標的にするかを監視するというものだった。攻撃の多くは、私自身が以前に例として示した攻撃[2]のバリエーションのように見える。
[2] http://antirez.com/news/96
また、晒されているあらゆるサービスのインスタンスを見つけるためにIPv4アドレス空間全体をスキャンすることは、極めて容易だという点も指摘しておく価値がある。例えばmasscanを使えばいい。とはいえ、20年前でも私自身のhpingを使って同じことができたし、実際に当時それをやって成功したのを覚えている。
要するに、インターネット上に開放されたRedisインスタンスが存在するのは、設定ミスが原因だ。攻撃者はそこに何らかのマイニングソフトウェアなどをインストールして利益を得ている。だが、話はそれだけではない……続きを読んでほしい。
保護モード
私見だが、セキュリティという分野はひどいものだ。私もその分野で働いていたことがあるが、それがアンダーグラウンドなものではなくなった頃に離れることにした。セキュリティ問題については誰もが持論を強く主張する一方で、たとえば現実のシステムに対してセキュリティ監査をきちんと行うといったことには、ほとんど真剣な関心が払われていない(ちなみにGoogle Project Zeroがその状況を少し変えつつあるが)。そんな中で、Redisが一時ファイル作成攻撃に対して脆弱だとするPGP暗号化メールを何度も受け取った末に、私は[2]のブログ記事を書いた。「たぶん君たちはRedisのセキュリティの本質を見誤っている」と伝えるためだ。数分のリサーチで見つけた、自分自身のシステムに対する攻撃をほぼそのまま公開したのだが、それは非常に深刻なものだった。メッセージは繰り返しになるが、Redisは外部に晒したまま使うようには設計されていないということだ。そして本当にハッカーごっこをしたいなら、もっと面白いことは他にある。しかしそうすることで、私は世界中に開放されている何千ものRedisインスタンスを破るための強力な武器を、スクリプトキディの手に渡してしまったのだ。
自分の過ちを償い、罪をあがなおうと、私は状況を少しでも改善するために何ができるかを考え始めた。Redis 3.xの一つの問題は、デフォルトですべてのIPアドレスで待ち受けることだった。そのため設定ミスが非常に起こりやすかった。ポートを開放したり、まったくファイアウォールを設定しなかったりするだけで、インスタンスは外部に晒されてしまうのだ。この問題に対するセキュリティ界のマントラは「安全なデフォルトで動かせ」というものだった。つまりRedisのようなネットワーク経由で使うキャッシュの場合、デフォルト設定ではほとんどの実ユーザーがそのままではまともに使えないようにしておけ、という考えだ。さらに悪いことに、何もわかっていない人は問題を解決するために安易に「bind *」としてしまい、結局振り出しに戻ってしまう。そこで私はもう少し賢い方法を探し、「protected mode」と名付けた機能を考え出した。家の前で何日もデモを続けた386プロセッサたちを大いにがっかりさせてしまったが。
保護モードの考え方は、すべてのアドレスで待ち受けつつも、ローカル以外からの接続に対しては、なぜ期待通りに動作しないのか、何をすべきか、そして保護モードを無効にして安易にインスタンスを全開放することに伴うリスクは何かを説明するエラーを返すというものだ。この機能がどのように動作するか、例を示そう。
$ nc 192.168.1.194 6379 -DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.
ここでの利点は次の通りだ。
- ユーザーがこの状況を解決するために何をすべきかがわかる。「connection refused」よりはるかにましだ。
- ユーザーがリスクを理解しないまま保護モードを無効にしたり、他にも解決策(パスワードを設定する、特定のインターフェースにバインドする)があることを知らずに済ませたりすることを防ごうとしている。
幻滅
だから私の淡い期待は、保護モードの方が安全なデフォルトよりも多少は役に立つのではないか、というものだった。しかし残念ながら、一定割合のユーザーはそもそも気にしないという事実はどうしようもない。中には自分がRedisをインストールしていることすら知らない人もいる。何か別のソフトウェアの依存関係の副作用としてそこに存在していたり、スクリプトによってインストールされたり、使っているABIイメージに最初から含まれていたりするのだ。
当初、Shodanで検索してみると、Redis 4.0の保護モードは実際にかなり効果を上げているように見えた。見つかった開放インスタンスのほとんどが「-DENIED」を返していたのだ。これは素晴らしいことだった。しかし[1]が公開された後、Shodanに(ちなみに彼らは最高で、Twitter上でもとても親切に対応してくれた)晒されているRedisインスタンスのバージョン別内訳をもらえないか頼んでみた。その結果、依然として大量のRedis 4.0インスタンスが晒されていることがわかった[3]。
[3] https://asciinema.org/a/8heQvivQkFmUrisbb9FQLfMBj
確かにその数は3.0のインスタンスよりは少ないが、それでも膨大だ。さらに調べてみると、デフォルトでインストールスクリプトがRedisの保護モードを*無効化*してしまうVMイメージさえ存在すると聞いた。セキュリティ機能が煩わしいと感じる人もいるからだ。とにかく箱から出してすぐネットワーク越しに動いてほしい。だから彼らはその煩わしさを取り除く。そうしてそのイメージが人気になり、多くの人が何が起きているかも知らずにそれをインストールし、Redis 4がインストールされたときには保護モードはオフで、インスタンスは晒された状態になっているのだ。
これは、ユーザーが簡単に無効化できてしまう「安全なデフォルト」についての教訓だと思う。ある程度は役に立つように見えるが、事故の件数を何割か減らす程度で、稀な例外にまで減らすことはできないのだ。
今後について
Redisのセキュリティモデルにおける根本的な問題の一つは、CONFIGコマンドのような特別なコマンドを使って、通常のAPI経由でサーバーを再設定できてしまうことだ。これはRedisの非常に価値ある機能だが、一度Redis APIへのアクセスを許してしまうとインスタンスへの侵入がはるかに容易になってしまう。そして通常のアプリケーションがRedisを使う上で、このレベルのアクセスは必要ない。
そこでRedis 6の開発の中で、ACLを導入することになる。今回も、この機能の導入は既存ユーザーにとって「痛みのない」ものになるようにしたい。何の認証情報もなしに接続した場合、Redisは自動的に「default」ユーザーでクライアントをログインさせる。このユーザーはアプリケーションが通常行うことはすべて実行できるが、管理コマンドはすべて拒否される。もちろん、設定を変えることでより厳格にしたり、特定のパターンに一致するキーに対して特定のコマンドのみを実行できる新しいユーザーを作成したりすることも可能になる。
Redis 6の開発の中では、SSL接続のサポートも統合する予定だ。ただし、デフォルトではRedisは暗号化なしで動作し、この機能はオプトインとなるため、ここで議論している問題に影響を与える可能性は低い。それでもSSLは、特定の環境においてより安全なRedis体験に向けた一歩前進でもある。
しかし私が期待を寄せているのはACLだ。何気なく使っているユーザーが、わざわざdefaultアカウントに管理コマンドを実行できる権限を与えるとは考えにくいからだ。特に、localhostからの接続は直接「admin」ユーザーとしてログインさせる予定だからだ。もしこれが思惑通りにいけば、Redis 6のインスタンスが晒されること自体は避けられないので今後も見かけることになるだろうが、少なくともシステム全体が侵害される難易度は上がるはずだ。少なくとも理論上は、だが。RedisのEVALコマンドはLuaスクリプトの実行を可能にするが、この機能はRedisの根幹をなすものなのでデフォルトで許可されるべきだ。Luaの実行環境はある程度サンドボックス化するよう努めているが、ITセキュリティをしばらく追ってきた人なら、サンドボックスは常に不完全で、封じ込めるための解決策というより、むしろいかに脱出するかを見つける練習のようなものだということを知っているだろう。今回は、主張のために攻撃手法を公開することは避けておこう。
記事をランダムに読む
コメント
ログインしてコメントする