在之前客户咨询案例中,很多客户应用程序连接sql server直接用的就是sa帐号。如果对数据库管理稍微严格一点的话,就不应该给应用程序这种权限,通常应用程序只需要进行增删改查,而很少有ddl操作,因此配置帐号时应该遵循“最小权限分配”的原则仅仅赋予所需的权限。
对于应用程序来说,最小的权限通常就是就是给予读权限,写权限和执行存储过程权限。由于为了防止sql注入导致的数据库信息泄漏,则还需要考虑拒绝帐号的查看定义权限,但值得注意的是,如果拒绝了查看定义的权限,则bulk insert会失败。完整的权限定义如下:
alter role [db_datareader] add member 用户名
alter role [db_datawriter] add member 用户名
grant execute to 用户名
deny view definition to 用户名
在sql server中,实例级别的是登录名,而数据库级别的才是用户名,登录名在创建完成后可映射到具体的库。因此我写了一个完整的脚本,同时创建登录名,用户,以及赋予对应的权限,脚本如下:
--创建用户的存储过程,
--示例exec sp_createuser 'username','rw','databasename'
--exec sp_createuser 'tesefx','r','test','0xe39ca97ebe03bb4ca5ff78e50374eebb'
create proc sp_createuser
@loginname varchar(50) ,
@iswrite varchar(3) ,
@databasename varchar(50),
@sid varchar(100) ='1'
as
print('示例:exec sp_createuser ''username'',''rw'',''databasename''')
print('示例:exec sp_createuser ''username'',''rwv'',''databasename'',''0xe39ca97ebe03bb4ca5ff78e50374eebb''')
print('r为只读权限,rw为读写权限,rwv为读写加view definition权限')
if exists ( select name
from sys.syslogins
where name = @loginname )
begin
print n'登录名已存在,跳过创建登录名步骤'
end
else
begin
declare @createlogin nvarchar(1000)
declare @pwd varchar(50)
print @sid
set @pwd=newid()
if(@sid='1')
begin
set @createlogin = 'create login [' + @loginname + '] with password=n'''
+ @pwd
+ ''', default_database=[master], check_expiration=off, check_policy=off;'
print n'登录名已创建,密码为:'+@pwd
end
else
begin
set @createlogin = 'create login [' + @loginname + '] with password=n'''
+ @pwd
+ ''', default_database=[master], check_expiration=off, check_policy=off,sid='+@sid+';'
print n'已经使用sid创建登录名:'+@loginname
end
exec (@createlogin)
--declare @sidtemp nvarchar(50)
--select @sidtemp=sid from sys.server_principals where name=@loginname
--print(n'登录名为:'+@loginname+n' sid为: 0x'+convert(varchar(50), @sidtemp, 2) )
end
declare @dynamicsql nvarchar(1000)
--切换数据库上下文
set @dynamicsql = n'use [' + @databasename + ']; ' + 'if exists(select name from sys.database_principals where name='''+@loginname+''') begin print(''用户名已存在,跳过创建用户名的步骤'') end else begin create user ['
+ @loginname + '] for login ' + @loginname + ' end;if ('''
+ @iswrite
+ '''=''rw'' or '''
+ @iswrite
+ '''=''rwv'') begin alter role [db_datareader] add member ' + @loginname
+ ';alter role [db_datawriter] add member ' + @loginname
+ '; end else begin alter role [db_datareader] add member '
+ @loginname + ';
alter role db_datawriter drop member '
+ @loginname + '
;end;grant execute to ' + @loginname + ';
if('''+@iswrite+'''<>''rwv'') begin deny view definition to ' + @loginname + '; end else begin grant view definition to ' + @loginname + '; end'
exec (@dynamicsql)
该存储过程用于创建应用程序连接sql server所需的登录名,用户以及对应权限,当用户或登录名存在时还会跳过该步骤,使用该存储过程的示例如:
exec sp_createuser 'username','rw','databasenam'
exec sp_createuser 'tesefx','r','test','0xe39ca97ebe03bb4ca5ff78e50374eebb'
上述执行的第一行是创建一个标准的帐号,账户名username,赋予对databasenam的库的读写权限,并返回生成的guid密码。第二个存储过程是使用第四个参数sid创建登录名,由于在alwayson或镜像的环境中,两端登录名需要有相同的sid,因此提供了在该情况下使用sid创建登录名的办法。