MongoDB最佳安全實踐

Tiger.Wang發表於2020-05-11

在前文[15分鐘從零開始搭建支援10w+使用者的生產環境(二)]中提了一句MongoDB的安全,有小夥伴留心了,在公眾號後臺問。所以今天專門開個文,寫一下關於MongoDB的安全。

一、我的一次MongoDB被黑經歷

近幾年,MongoDB應用越來越多,MongoDB也越來越火。

從2015年開始,MongoDB被一些「非法組織/黑客」盯上了。他們的做法也很簡單,連到你的資料庫上,把你的資料拿走,然後把你的庫清空,留一個訊息給你,索要比特幣。

跟最近流行的勒贖病毒一個套路。

我在某個雲上有一臺伺服器,主要用來做各種研究和測試,隨時可以格了重灌的那種。上面跑著一個MongoDB,是用預設的引數簡單啟動的一個單例項。

早上起來,跑程式測試時,程式直接報錯。

跟蹤程式碼,發現是頭天寫進去的資料不見了。

進到資料庫,發現資料庫都在,但裡面的表全被清空了,多了一個Readme的表。檢視這個表的內容:

> db.Readme.find().pretty()
{
        "_id" : "5c18d077fd42b92d8f6271c3",
        "BitCoin" : "3639hBBC8M7bwqWKj297Jc61pk9cUSKH5N",
        "eMail" : "mongodb@tfwno.gf",
        "Exchange" : "https://localbitcoins.com",
        "Solution" : "Your database is downloaded and backed up on our secured servers. To recover your lost data: Send 0.2 BTC to our BitCoin address and Contact us by eMail with your server IP address and a proof of Payment. Any eMail without your IP address and a proof of Payment will be ignored. Your are welcome!"
}

簡單來說,這是一個通知:你的資料被我們綁架了,想要贖回去,需要0.2個比特幣。

一身冷汗。如果這是一個生產環境,如果這是一個系統的運營資料,後果不堪設想。

究其原因,這個資料庫在啟動時,用了預設的引數,未加任何防護。

所以,

一定不要用預設的設定執行MongoDB資料庫!

一定不要用預設的設定執行MongoDB資料庫!

一定不要用預設的設定執行MongoDB資料庫!

二、安全實踐

1. 修改埠

MongoDB啟動時,使用了幾個預設的埠:

27017: 用於一般的單例項(mongod),或者叢集中路由伺服器(mongos)

27018: 用於叢集中的分片伺服器

27019: 用於叢集中的配置伺服器

實際佈署時可以把預設埠換成別的埠。

命令列:

$ ./mongod --port port_number

配置檔案:

port=port_number

2. 繫結IP

這個要區分一下MongoDB的版本。

查詢MongoDB版本的命令:

$ ./mongod --version

在MongoDB Version 3.6之前,MongoDB啟動時預設繫結到伺服器的所有IP上。換句話說,通過所有的IP都可以訪問資料庫,這兒的安全隱患在於外網IP。

在3.6之後,MongoDB啟動預設繫結127.0.0.1,從外網無法訪問,去掉了這個隱患。

設定繫結IP,命令列:

$ ./mongod --bind_ip your_ip #單IP繫結

$ ./mongod --bind_ip your_ip1,your_ip2 #多IP繫結

配置檔案:

bind_ip=your_ip #單IP繫結

bind_ip=your_ip1,your_ip2 #多IP繫結

MongoDB還提供了一個一次繫結所有IP的引數。命令列:

$ ./mongod --bind_ip_all

配置檔案:

bind_ip_all=true

另外,繫結時,your_ip也可以換成域名your_host,效果是一樣的。

在生產環境中,出於安全的需要,通常可以設定資料庫繫結到伺服器的內網IP,供資料層運算元據庫就好。如果有特殊需要,可以臨時繫結到外網IP,操作完成後再去掉。

資料庫切換繫結IP和埠,對資料庫本身沒有任何影響。

3. 資料庫伺服器內部身份認證

資料庫伺服器的內部身份認證,是更高一個層次的安全策略,用於保證主從/複製集/叢集中各個資料庫伺服器的安全合法接入。

內部身份認證,首先需要有一個數字金鑰。

數字金鑰可以使用機構簽發的證照來生成,也可以使用自生成的金鑰。

當然在低安全級別的情況下,你也可以隨手寫一個金鑰來使用。

自生成金鑰的生成命令:

$ openssl rand -base64 756 > path_to_keyfile

然後設定金鑰檔案的讀寫許可權:

$ chmod 400 path_to_keyfile

看一下金鑰檔案:

$ ls -l
-rw-r--r--  1 test  test  1024  5 10 17:51 test.key

下面,為資料庫啟用金鑰檔案。命令列:

$ ./mongod --keyFile path_to_keyfile

配置檔案:

keyFile=path_to_keyfile

注意:

  • 內部認證用在多於一個伺服器的情況,例如:主從/複製集/叢集上,做伺服器之間的互相認證。單個伺服器可做可不做,實際上無效。

  • 內部認證要求認證的伺服器使用相同的金鑰檔案。也就是說,所有的伺服器使用同一個金鑰檔案。

  • 金鑰檔案有安全要求,檔案許可權必須是400,否則資料庫啟動時會有報錯。

4. 使用者和角色鑑權

MongoDB支援為資料庫建立使用者和分配角色,用使用者和角色來管理和使用資料庫。

MongoDB建立使用者操作和上面不同。上邊的內容,是在資料庫執行以前進行,而建立使用者,是在資料庫執行以後。

$ ./mongo your_ip:your_port
> use admin
switched to db admin
> db.createUser({"user" : "user_name""pwd" : "user_password","roles" : [{"role" : "userAdminAnyDatabase""db" : "admin"}]})
Successfully added user: {
    "user" : "user_name",
    "roles" : [
        {
            "role" : "userAdminAnyDatabase",
            "db" : "admin"
        }
    ]
}

這樣我們就加入了一個使用者。

MongoDB內建的角色分以下幾類:

  • 超級使用者:root
  • 資料庫使用者角色:read、readWrite
  • 資料庫管理角色:dbAdmin、dbOwner、userAdmin
  • 叢集管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager
  • 可操作所有資料庫角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
  • 備份、恢復角色:backup、restore

角色不詳細解釋了,角色名稱的英文寫的很明白。

在實際操作中,通常會將使用者建在admin中,用roles裡的db來指定使用者可以使用或管理的資料庫名稱。

通過這一通操作,我們已經在資料庫中建立好了使用者。下面需要伺服器啟用鑑權。

命令列:

./mongod --auth

配置檔案:

auth=true

這個用於mongod啟動的資料庫。對於叢集的router,即mongos,會預設啟用auth,所以不需要顯式啟用。

當MongoDB啟用鑑權後,再用mongo客戶端連線資料庫,就需要輸入使用者帳號資訊了。

$ ./mongo -u user_name -p user_password your_ip:your_port/admin

$ ./mongo -u user_name -p your_ip:your_port/admin #提示輸入密碼

同樣,在程式碼中,資料庫連線串也同步變成了:

"MongoConnection""mongodb://user_name:user_password@localhost:27017/admin?wtimeoutMS=2000"

三、總結

一般來說,做完上面的安全處理,就可以完全滿足生產環境的安全要求了。

再高的要求,可以通過啟用TLS來強化。這會是另一個文章。

 


 

老王Plus

微信公眾賬號:老王Plus

如果你想及時得到個人文章以及內容的訊息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號)。

本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。

 

相關文章