Clarifications on the Incapsula Redis security report

Salvatore Sanfilippo

IncapsulaのRedisセキュリティレポートについての補足

数日前、朝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サーバーのようなものだと考えていただければ分かりやすいでしょう。違うのは、そこにあるのがHTTPではなく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.

この方式の利点は次の二点です。

  1. ユーザーはこの状況を解消するために何をすべきかが分かります。「connection refused(接続拒否)」とだけ表示されるよりはるかに親切です。
  2. 保護モードを無効にすることに伴うリスクを理解せず、また他にも解決策(パスワードを設定する、特定のインターフェースにバインドする)があることを知らずに、安易に無効化してしまうことを防ごうとしています。

幻滅

私の幻想は、もしかすると安全なデフォルトよりも役に立つのではないか、というものでした。しかし残念ながら、一定の割合のユーザーはそもそも気にかけない、Redisをインストールしていることすら知らない人もいる、という事実はどうしようもありません。何か別のソフトウェアの依存関係として副作用的にそこにあるだけだったり、スクリプトによってインストールされたり、使っているVMイメージに最初から含まれていたりするのです。

当初、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のセキュリティモデルにおける根本的な問題の一つは、通常のAPI経由で、CONFIGコマンドのような特別なコマンドを使ってサーバーを再設定できてしまうことです。これはRedisにとって非常に価値のある機能ですが、RedisのAPIにアクセスできてしまえばインスタンスへの侵入がはるかに容易になってしまいます。一方で、Redisを利用する通常のアプリケーションは、そこまでの権限を必要としません。

そこでRedis 6の開発の中で、ACLを導入する予定です。繰り返しになりますが、この機能も既存のユーザーにとって負担のない形で導入しようと考えています。認証情報なしで接続すると、Redisは自動的に「default」ユーザーとしてクライアントをログインさせます。このdefaultユーザーは、アプリケーションが通常行うことはすべて実行できますが、すべての管理コマンドは拒否されます。もちろん、より厳格に設定することも可能ですし、特定のパターンに一致するキーに対して特定のコマンドのみを実行できる新しいユーザーを作成することもできます。

Redis 6ではSSL接続のサポートも統合する予定です。こちらは今回議論している問題にはあまり影響しないでしょう。デフォルトではRedisは暗号化なしで動作し、この機能はオプトインになるからです。とはいえ、SSLも特定の環境ではより安全なRedis体験に向けた一歩ではあります。

しかし私が期待を寄せているのはACLです。たまたまRedisを使っている一般的なユーザーが、defaultアカウントに管理コマンドを実行できる権限を与えるとは考えにくいからです。特に、ローカルホストからの接続は直接「admin」ユーザーとしてログされるようにする予定だからです。もし目論見通りにいけば、Redis 6のインスタンスも晒された状態で見つかることは避けられないでしょうが、少なくともそれらのインスタンスではシステム全体が侵害される難易度は上がるはずです。少なくとも理論上は、ですが。RedisのEVALコマンドはLuaスクリプトの実行を可能にし、この機能はRedisの根幹をなすものなのでデフォルトで許可されるべきです。私たちはある程度サンドボックス化されたLua実行環境を用意しようとしていますが、ITセキュリティをしばらく追ってきた方なら、サンドボックスは常に不完全であり、封じ込めの解決策というよりは、むしろいかに脱出するかを見つける試みに近いことをご存じでしょう。ただ今度は、主張のために攻撃手法を公開することは避けようと思います。

原文は Salvatore Sanfilippo により に公開されました。

この記事は「muse-spark-1.2-contributor」を使用して翻訳されました。