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)兩部分組成。
許可權:在哪裡+做什麼
資源:
- 叢集級別:
{ cluster: true }
; - 資料庫級別:
{ db: "test", collection: "" }
; - 表級別:
{ db: "test", collection: "user" }
;
Privilege Actions 定義User能夠在資源上執行的操作。
例如:MongoDB在文件級別上執行的讀寫操作列表是:find,insert,remove,update
;
2.2 mongo 內建的角色:
- 普通資料庫使用者的角色:
- read:只讀資料的許可權
- readWrite:讀寫資料的許可權
- 跨庫角色:除config和local之外所有的資料庫:
- readAnyDatabase:在所有資料庫上讀取資料的許可權
- readWriteAnyDatabase:在所有資料庫上讀寫資料的許可權
- userAdminAnyDatabase:在所有資料庫上管理User的許可權
- dbAdminAnyDatabase:管理所有資料庫的許可權
- 資料庫管理角色:
- userAdmin:在當前DB中管理User
- dbAdmin:在當前dB中執行管理操作
- dbOwner:在當前DB中執行任意操作
- 超級角色:
- userAdmin
- userAdminAnyDatabase
- root
- 叢集管理角色:
- clusterMonitor:授予監控叢集的許可權,對監控工具具有readonly的許可權
- clusterAdmin:授予管理叢集的最高許可權
- clusterManager:授予管理和監控叢集的許可權
- hostManager:管理Server
- 備份恢復角色:
- backup
- restore
- 內部角色:
- __system
- __queryableBackup
- 分片角色:
- enableSharding
3. 角色
3.1 建立角色
db.createRole(<role>, <writeConcern>)
<role>
: 角色定義文件
<writeConcern>
: 寫安全級別
在建立角色時,必須明確Role的四個特性:
Scope
:角色作用的範圍,
- 建立在Admin中的角色,能夠在其他DB中使用;在其他DB中建立的角色,只能在當前DB中使用;
- 在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
歡迎關注文章同步公眾號"黑桃"