为了账号安全,请及时绑定邮箱和手机立即绑定

mongo-06-数据库安全

标签:
MongoDB

数据库安全涉及到两个方面,一是身份认证,二是鉴权。

mongodb安装完后默认是不开启auth安全模块的,直接通过 mongo工具或者其他工具不需要身份认证就可以成功连接mongo服务。

1 开启安全模式 --auth

为了安全起见,我们需要开启安全模式 --auth

[root@docker01 ~]# /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
[root@docker01 ~]# 

这时,我们连接来读取 test 数据库的集合,发现读取失败。

[root@docker01 ~]# /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 数据库的集合

[root@docker01 ~]# /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");

[root@docker01 ~]# /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"
})
> 
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消