1. 程式人生 > 其它 >mongo-06-資料庫安全

mongo-06-資料庫安全

技術標籤:005-mongo實戰mongodb

資料庫安全涉及到兩個方面,一是身份認證,二是鑑權。

mongodb安裝完後預設是不開啟auth安全模組的,直接通過 mongo工具或者其他工具不需要身份認證就可以成功連線mongo服務。

1 開啟安全模式 --auth

為了安全起見,我們需要開啟安全模式 --auth

[[email protected] ~]# /usr/local/mongodb-4.4.3/bin/mongod -f /usr/local/mongodb-4.4.3/mongodb.conf --auth
about to fork child process, waiting until server is ready for connections.
forked process: 4195
child process started successfully, parent exiting
[
[email protected]
~]#

這時,我們連線來讀取 test 資料庫的集合,發現讀取失敗。

[[email protected] ~]# /usr/local/mongodb-4.4.3/bin/mongo --host localhost --port 27017
MongoDB shell version v4.4.3
connecting to: mongodb://localhost:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("5106e9d5-4480-414b-b0b5-6c6b729028ab") }
MongoDB server version: 4.4.3
> use test
switched to db test
> show collections
Warning: unable to run listCollections, attempting to approximate collection names by parsing connectionStatus
> 

MongoDB將所有角色資訊儲存在admin資料庫的admin.system.roles集合中。一般,切換到admin資料庫,建立角色,新增使用者。

建立一個管理員使用者 root,密碼也是 root(建立使用者細節下面詳解)。

> use admin
switched to db admin
> db.createUser({ user: "root", pwd: "root", roles: [{ role: "userAdminAnyDatabase", db: "admin" }] })
Successfully added user: {
	"user" : "root",
	"roles" : [
		{
			"role" : "userAdminAnyDatabase",
			"db" : "admin"
		}
	]
}
> 

1.1 身份認證

方式一:
mongo -u <username> -p <password> --authenticationDatabase <db>

身份認證後,可以檢視 test 資料庫的集合

[[email protected] ~]# /usr/local/mongodb-4.4.3/bin/mongo --host localhost --port 27017 -u root -p root --authenticationDatabase admin
MongoDB shell version v4.4.3
connecting to: mongodb://localhost:27017/?authSource=admin&compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("89008f1d-7278-4387-9992-7ff1054a7d3f") }
MongoDB server version: 4.4.3
> use test
switched to db test
> show collections
outDoc
user
> 

方式二:

不指定使用者名稱密碼連線上mongo,然後使用 db.auth("username","password");

[[email protected] ~]# /usr/local/mongodb-4.4.3/bin/mongo --host localhost --port 27017
MongoDB shell version v4.4.3
connecting to: mongodb://localhost:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("3736b07f-4793-4dcb-8af8-ca48d9f508f7") }
MongoDB server version: 4.4.3
> use admin
switched to db admin
> db.auth("root","root")
1
> show collections
system.users
system.version
> show databases
admin   0.000GB
config  0.000GB
local   0.000GB
test    0.000GB
> 

2. 許可權和內建角色

2.1 許可權

MongoDB的許可權包由:資源(Resource)和操作(Action)兩部分組成。
許可權:在哪裡+做什麼

資源:

  1. 叢集級別:{ cluster: true };
  2. 資料庫級別:{ db: "test", collection: "" };
  3. 表級別:{ db: "test", collection: "user" };

Privilege Actions 定義User能夠在資源上執行的操作。
例如:MongoDB在文件級別上執行的讀寫操作列表是:find,insert,remove,update;

2.2 mongo 內建的角色:

  1. 普通資料庫使用者的角色:
  • read:只讀資料的許可權
  • readWrite:讀寫資料的許可權
  1. 跨庫角色:除config和local之外所有的資料庫:
  • readAnyDatabase:在所有資料庫上讀取資料的許可權
  • readWriteAnyDatabase:在所有資料庫上讀寫資料的許可權
  • userAdminAnyDatabase:在所有資料庫上管理User的許可權
  • dbAdminAnyDatabase:管理所有資料庫的許可權
  1. 資料庫管理角色:
  • userAdmin:在當前DB中管理User
  • dbAdmin:在當前dB中執行管理操作
  • dbOwner:在當前DB中執行任意操作
  1. 超級角色:
  • userAdmin
  • userAdminAnyDatabase
  • root
  1. 叢集管理角色:
  • clusterMonitor:授予監控叢集的許可權,對監控工具具有readonly的許可權
  • clusterAdmin:授予管理叢集的最高許可權
  • clusterManager:授予管理和監控叢集的許可權
  • hostManager:管理Server
  1. 備份恢復角色:
  • backup
  • restore
  1. 內部角色:
  • __system
  • __queryableBackup
  1. 分片角色:
  • enableSharding

3. 角色

3.1 建立角色

db.createRole(<role>, <writeConcern>)
<role> : 角色定義文件
<writeConcern> : 寫安全級別

在建立角色時,必須明確Role的四個特性:

  • Scope :角色作用的範圍,
  1. 建立在Admin中的角色,能夠在其他DB中使用;在其他DB中建立的角色,只能在當前DB中使用;
  2. 在admin 資料庫中建立的角色,Scope是全域性的,能夠在admin,其他DB和叢集中使用,並且能夠繼承其他DB的Role;而在非admin中建立的角色,Scope是當前資料庫,只能在當前DB中使用,只能繼承當前資料庫的角色。
    因此建立角色,一般都在admin庫中建立。
  • Resource :角色控制的資源,表示授予在該資源上執行特定操作的許可權;
  • Privilege Actions :定義了User能夠在資源上執行的操作,系統定義Action是:Privilege Actions;
  • Inherit :角色能夠繼承其他角色許可權;

role文件格式如下

{
  role: "<name>",	//角色名
  privileges: [ //許可權陣列,包括資源和許可權操作
     { resource: { <resource> }, actions: [ "<action>", ... ] },
     ...
  ],	
  roles: [//父類角色陣列,對於該資料庫角色可直接用role字串表示
     { role: "<role>", db: "<database>" } | "<role>",
      ...
  ],	
  authenticationRestrictions: [ //認證限制陣列,可選,確定一組可連線IP地址、CIDR範圍
    {
      clientSource: ["<IP>" | "<CIDR range>", ...],
      serverAddress: ["<IP>" | "<CIDR range>", ...]
    },
    ...
  ]		
}

建立一個針對 test 資料庫user集合的只讀角色 testRead

> use admin
> db.createRole(
...    {
...      role: "testRead",
...      privileges: [
...        { resource: { db: "test", collection: "user" }, actions: [ "find",  "listCollections","listIndexes"] }
...      ],
...      roles: []
...    }
... );
{
	"role" : "testRead",
	"privileges" : [
		{
			"resource" : {
				"db" : "test",
				"collection" : "user"
			},
			"actions" : [
				"find",
				"listCollections",
				"listIndexes"
			]
		}
	],
	"roles" : [ ]
}
>

3.2 檢視角色

檢視所有角色

show roles

> show roles
{
	"role" : "__queryableBackup",
	"db" : "admin",
	"isBuiltin" : true,
	"roles" : [ ],
	"inheritedRoles" : [ ]
}
...
...
> 

檢視具體的角色

db.getRole(<RoleName>)

檢視內建的 read 角色

> db.getRole("read")
{
	"role" : "read",
	"db" : "admin",
	"isBuiltin" : true,
	"roles" : [ ],
	"inheritedRoles" : [ ]
}
> 

檢視上面建立的 testRead 角色的具體資訊 {showPrivileges: true}

> db.getRole("testRead",{showPrivileges: true})
{
	"role" : "testRead",
	"db" : "admin",
	"isBuiltin" : false,
	"roles" : [ ],
	"inheritedRoles" : [ ],
	"privileges" : [
		{
			"resource" : {
				"db" : "test",
				"collection" : "user"
			},
			"actions" : [
				"find",
				"listCollections",
				"listIndexes"
			]
		}
	],
	"inheritedPrivileges" : [
		{
			"resource" : {
				"db" : "test",
				"collection" : "user"
			},
			"actions" : [
				"find",
				"listCollections",
				"listIndexes"
			]
		}
	]
}
> 

3.3 修改角色

db.updateRole(<roleName>, <roleDocument>)

將 testRead 角色修改為針對整個test資料庫只讀

> db.updateRole("testRead",
...    {
...      privileges: [
...        { resource: { db: "test", collection: "" }, actions: [ "find",  "listCollections","listIndexes"] }

...      ],
...      roles: []
...    }
... );
> 

檢視修改後 testRead 角色的詳細資訊

> db.getRole("testRead",{showPrivileges: true})
{
	"role" : "testRead",
	"db" : "admin",
	"isBuiltin" : false,
	"roles" : [ ],
	"inheritedRoles" : [ ],
	"privileges" : [
		{
			"resource" : {
				"db" : "test",
				"collection" : ""
			},
			"actions" : [
				"find",
				"listCollections",
				"listIndexes"
			]
		}
	],
	"inheritedPrivileges" : [
		{
			"resource" : {
				"db" : "test",
				"collection" : ""
			},
			"actions" : [
				"find",
				"listCollections",
				"listIndexes"
			]
		}
	]
}
> 

3.4 刪除角色

db.dropRole("roleName")

建立test資料庫的寫角色 testWrite,然後刪除 testWrite 角色,再次檢視,返回null,表示角色不存在

#使用管理員 root 使用者進行操作
> db.auth("root","root")
1
# 建立角色 testWrite
> db.createRole(
...    {
...      role: "testWrite",
...      privileges: [
...        { resource: { db: "test", collection: "" }, actions: [ "insert", "update","remove"] }
...      ],
...      roles: []
...    }
... );
{
	"role" : "testWrite",
	"privileges" : [
		{
			"resource" : {
				"db" : "test",
				"collection" : ""
			},
			"actions" : [
				"insert",
				"update",
				"remove"
			]
		}
	],
	"roles" : [ ]
}
# 檢視 testWrite 角色
> db.getRole("testWrite")
{
	"role" : "testWrite",
	"db" : "admin",
	"isBuiltin" : false,
	"roles" : [ ],
	"inheritedRoles" : [ ]
}
# 刪除 testWrite 角色
> db.dropRole("testWrite")
true
# 再次檢視,返回null,表示角色不存在
> db.getRole("testWrite")
null
> 

4. 建立使用者

db.createUser(<user>, <writeConcern>)
<user> : 驗證和訪問資訊
<writeConcern> : 安全寫級別

user文件格式如下:

{
  user: "<name>",	//使用者名稱
  pwd: "<cleartext password>",	//使用者密碼
  customData: { <any information> },	//備註資訊,可選
  roles: [//角色陣列,授權給此使用者的角色,空陣列[]表示無角色
    { role: "<role>", db: "<database>" } | "<role>",
    ...
  ],	
  authenticationRestrictions: [//限制陣列,可選
     {
       clientSource: ["<IP>" | "<CIDR range>", ...]
       serverAddress: ["<IP>" | "<CIDR range>", ...]
     },
     ...
  ],	
  mechanisms: [ "<SCRAM-SHA-1|SCRAM-SHA-256>", ... ],		//指定用於建立SCRAM使用者憑據的特定SCRAM機制,可選。3.6預設SCRAM-SHA-1
  passwordDigestor: "<server|client>" //密碼摘要,可選,指定使用者端/伺服器是否生成密碼摘要
}	

使用上面的 testRead角色,建立一個針對test資料庫的只讀使用者, 名字叫做 testRead,密碼也是 testRead。

> user admin
> db.createUser({ user: "testRead", pwd: "testRead", roles: [{ role: "testRead", db: "admin" }] })
Successfully added user: {
	"user" : "testRead",
	"roles" : [
		{
			"role" : "testRead",
			"db" : "admin"
		}
	]
}

對上面建立的 testRead 使用者進行身份認證,然後檢視test資料庫集合,檢視user集合內容。因為只有讀許可權,所以插入文件時,報錯"Unauthorized",未授權。

# 身份認證
> db.auth("testRead","testRead")
1
> use test
switched to db test
# 檢視資料庫中的集合
> show collections
outDoc
user
# 可以檢視user集合內容
> db.user.find()
{ "_id" : "1", "money" : 1500, "name" : "劉一一", "gender" : "女" }
{ "_id" : "2", "money" : 1000, "name" : "陳二", "gender" : "女" }
{ "_id" : "3", "name" : "張三", "sal" : 1000, "gender" : "女" }
{ "_id" : "4", "money" : 800, "name" : "李四", "gender" : "女" }
{ "_id" : "5", "money" : 1000, "name" : "王五", "sal" : 500, "gender" : "女" }
{ "_id" : "6", "name" : "趙六", "money" : 1000 }
{ "_id" : "7", "money" : 1000, "name" : "孫七", "gender" : "女" }
{ "_id" : ObjectId("5fff6a78025e5d9ea86e18cc"), "money" : 1000, "name" : "周八", "gender" : "女" }
{ "_id" : { "age" : 18, "gender" : "男" }, "money" : 1000, "name" : "吳九", "gender" : "女" }
{ "_id" : ObjectId("5fff95783f6d5ed2fcce4133"), "money" : 2000, "name" : "ZHANG", "addr" : [ "三亞", "北京" ], "gender" : "女" }
{ "_id" : ObjectId("60045f5719414c7b5be4c122"), "name" : "富二代", "money" : 1500 }
{ "_id" : ObjectId("6004611c19414c7b5be4c13f"), "name" : "打工人", "money" : 800 }
{ "_id" : ObjectId("6004c82e21bca04a14f52bee"), "money" : 1100 }
{ "_id" : ObjectId("6004ce5521bca04a14f52bf0"), "money" : 1200 }
{ "_id" : ObjectId("6004ce8f21bca04a14f52bf1"), "money" : 1300, "name" : null }
# 插入文件失敗,未授權
> db.user.insert({name:"只讀使用者"})
WriteCommandError({
	"ok" : 0,
	"errmsg" : "not authorized on test to execute command { insert: \"user\", ordered: true, lsid: { id: UUID(\"3736b07f-4793-4dcb-8af8-ca48d9f508f7\") }, $db: \"test\" }",
	"code" : 13,
	"codeName" : "Unauthorized"
})
> 

[慕課手記同步:mongo-06-資料庫安全] https://www.imooc.com/article/314521


歡迎關注文章同步公眾號"黑桃"

在這裡插入圖片描述