読者です 読者をやめる 読者になる 読者になる

UTALI

書き溜めておいた技術記事や旅行記のバックアップです。

MongoDBの安全な使い方ガイド

MongoDBはNoSQLとしては最も普及しています。非常に高速、高性能であり、スキーマレスな柔軟性を兼ね備えています。しかし一方で、セキュリティが弱い、などの根拠のないデマも流れています。しかし実際は適切な設定を行えば、MySQLなどのRDBMSに比較しても、むしろ安全です。

以下のチェックリストをすべて確認してください。ここに書かれている事項をすべて満たしている限り、あなたの使用しているMongoDBがクラッカーの餌食になることは、まずないはずです。

ユーザーを作成してパスワードを設定する

いきなりこのような初歩的な指摘をされて驚く人も多いかもしれません。しかし、実際には企業のシステムがパスワードの設定を忘れたがために、個人情報を流失させてしまった事例があります。

Mac OS X向けのセキュリティソフト「MacKeeper」の提供元であるKromotechのサーバー設定に不備があり、MacKeeperユーザーのアカウント情報に外部からアクセスできる状態になっていたという(ZDNet Japan)。

アクセスできたアカウント情報は1300万人分とのこと。これを明らかにしたセキュリティ研究者によると、KromtechのサーバーではMongoDBが稼働しており、その27017ポートに外部から接続して格納されている情報にアクセスできる状況になっていたとのこと。すでにKromtech側は対応を行ったと発表、クレジットカード情報の流出はないともしている。

MongoDBでは明示的に設定をおこなわない限り、ユーザーやIPアドレスによるアクセス制限が行われない。そのため、通常はアクセスを制限するため内部ネットワーク上でサーバーを運用したり、アクセス制限の設定を行うのが一般的だが、これを怠っていたようだ。

MongoDBでは、特にセキュリティを必要としない用途(たとえばプライベートで使用するクローラーのストレージなど)での利便性から、デフォルトで特にアクセス制限を設けていません。注意しましょう。

実際にユーザーを作成してパスワードを設定する例をここで実践してみます。 まず最初にmongodbの認証を無効化します。

sudo vim /etc/mongodb.conf

auth = trueコメントアウトしてnoauth= trueを有効化

# Turn on/off security.  Off is currently the default

noauth = true

#auth = true
mongo

そしてユーザーを作成したいデータベースに移動します。

>use {データーベース 名}

エラーが出なければユーザーを作成します。

db.createUser(
    {
      user: "ユーザ名",
      pwd: "パスワード",
      roles: [
        { 
          role: "readWrite",
          db: "データベース名" 
        }
      ]
    }
)

解説

説明
user ユーザー名を指定します。
pwd パスワードを指定します。
roles データベースとその操作権限を指定します。1つのユーザーに対して複数のデータベースを指定することが可能です。一般ユーザーに対してはreadWriteを指定することが一般的です。

次に認証がうまくいくか確認します。 先ほど指定したユーザー名とパスワードを覚えておいてください。

> db.auth("{ユーザー名}","{パスワード}")
> 1

1が出力されたら成功です。

認証モードに変更する。 最後に認証モードをONにします。こうすることでMongoDBにアクセスする際はユーザー名とパスワードを入力することになり、安全性が上昇します。

sudo vim /etc/mongodb.conf

noauth = trueコメントアウトしてauth= trueを有効化

# Turn on/off security.  Off is currently the default

#noauth = true

auth = true

この時点では認証モードは有効化されていません。再起動すると以後認証モードになります。

なおExpressからMongoDBに接続する場合は以下のようにしてください。

mongoclient を使用する場合は

mongoClient.connect("mongodb://{user}:{password}@{host}:{port}/{dbname}"function(err,db){
//処理を行う
} );

もう一つの方法

mongoclient.open(function(err, mongoclient) {

  // Then select a database
  var db = mongoclient.db("exampledatabase");

  // Then you can authorize your self
  db.authenticate('username', 'password', function(err, result) {
    // 認証済みなら result=true
    // 認証していない場合 result=false

    // If authorized you can use the database in the db variable
  });
});

デフォルトのポート番号27017を使わない

MongoDBのデフォルトの設定ではポート番号27017を使用しています。そしてこの27017番を標的にしたポートスキャン行為が横行しています。実際に攻撃用のツールも出回り、被害も出ているようです。

以下は警視庁のレポートからの引用です。

インターネット上に不用意に公開されている MongoDB を探索する目的と考えられるアクセ スが増加しています。MongoDB を利用している企業や組織においては、インターネットへの 不要な公開を停止する、適切な認証を実施する等の対策を実施することを推奨します。

インターネット上に不用意に公開されている MongoDB について

MongoDB は米国 MongoDB 社によって開発され、オープンソースで公開されているデータベースソフトウェアです。 2月10 日、ドイツのザールランド大学のグループが、インターネット経由で外部から認証を 必要とせずにアクセスすることができる MongoDB データベースを約4万件確認したとの研究 結果を公表iしました。同研究結果では、実際に膨大な顧客情報が外部から参照可能となっ ていたデータベースも存在したと指摘しています。また、日本国内のIP アドレスにおいても、 外部から参照可能なデータベースが確認されていることが報告されています。 なお、同グループは本件についてMongoDB社に責任があるものではなく、利用者の不適切な設定に原因があるとしています。 MongoDBの探索行為と考えられるアクセスの増加について MongoDBは初期設定では 27017/TCP ポートを使用します。警察庁の定点観測システム においても、宛先ポートを 27017/TCP とするアクセスの発信元 IP アドレス数が、2月 13 日か ら大きく増加しています(図1)。 また、アクセスの内容に着目すると、2月12 日までは単にポートの開放状況を確認するポ ートスキャン行為が大多数を占めており、同一発信元IP アドレスから他の複数のポートに対してもポートスキャン行為が行われていることが確認できました。

このためMongoDBを起動する時には、任意の別のポートを利用することを推奨します。この場合はユーザー設定の40000~60000番台の任意の番号を設定すべきでしょう。

任意のポートを指定して起動するときは、オプションの--portで番号を指定します。

この構文は以下の通りです。

mongod —port {ポート番号}

以外に忘れてしまいがちなのは、ほかのアプリケーションからMongoDBを利用するときに変更したポート番号を指定することです。

たとえば、ターミナルからアクセスするときは--portで番号を指定します

mongo —port {ポート番号}

アクセス制限を有効化する

前に説明したようにMongoDBはデフォルトでで特にアクセス制限が設けられていません。アクセス制限を有効化するには/etc/mongod.confauth = trueコメントアウトを除去します




bind_ipの設定を有効化する

デフォルトではMongoDBはサーバーの外部からアクセスすることが可能です。これは用途によっては便利な機能ですが、WEBサービスのデータベースとして利用する場合には脆弱性となります。実際に大企業のシステムでこの設定を怠ったがために、個人情報を流失させてしまった例があります。

以下は引用です

サンリオは12月23日、「サンリオタウン」などの会員情報330万件を格納するデータベースが外部からインターネットで閲覧可能状態であったと報じられたことに対し、会員情報の流出はないと明らかにした。2015年12月19日にサンリオタウンのデータベース露出に関する記事がCSO >Onlineに掲載され、氏名、生年月日、出身国、メールアドレス、SHA1によりハッシュ化された、パスワードのヒント、ポイントデータなどが格>納されたデータベースが外部からアクセス可能な状態であったという。 原因としては利用しているサンリオタウンで利用しているMongoDBの設定ミスで、bind_ip(外部からの接続設定をおこなう設定)がデフォルトのままで外部からの接続を全て受け付ける状態であったと推測されている。

通常の用途(たとえば海外では非常に人気のあるMEANスタック、つまりMongoDBをデータベース、Node.jsとExpressをサーバーとして利用する)ではローカルホストのIP、127.0.0.1、に設定します。

sudo vim /etc/mongod.conf

これを以下のように設定します

# Listen to local interface only. Comment out to listen on all interfaces.
bind_ip=127.0.0.1  

設定を反映します。

sudo mongod -f /etc/mongod.conf --shutdown
sudo mongod -f /etc/mongod.conf

ポートの状態を確認します

netstat -ant | grep {MongoDBのポート番号}

比較的新しいバージョンのMongoDBはデフォルトでこの設定をしてありますが、古いバージョンではこの設定が無効化されている場合があります。どちらにしても念の為に設定を確認しておく必要がありそうです。

OSのrootユーザーでMongoDBを起動しない

これはMongoDBに限らないことですが、rootでアプリケーションを起動させることは避けましょう。

mongoose、pymongoなどのアクセスライブラリを使用する

RDBMSに比べて後発であるNoSQLはその仕様上、インジェクションなどの攻撃に対して高い防御性能を備えています。しかし、だからと言ってMongoDBに対してインジェクション攻撃をすることができないわけではありません。たとえば、演算子をクエリに混入させたり、任意のJavaScriptコードを実行させることです。mongooseのようなアクセスライブラリは、エスケープなどの十分なセキュリティ対策を取っており、しかも開発コミュニティも非常に活発であるので、安全にMongoDBを利用することが可能です。

PHPの利用を避ける

またPHP煽りかと不快に思われた方もいるかもしれません。 しかし、実際にPHPでMongoDBを利用する時に使用される際には言語仕様による固有の脆弱性 が確認されています。

これに対するもっとも優れた安全対策は、PHPでMongoDBを利用しないことです。MongoDBを利用する際に選択すべき言語は、Node.js、PythonRubyScalaなどで、これらのコミュニティでは、活発にMongoDBが利用されており、それゆえに安全対策が十分に取られています。