1 身份认证
身份认证
大部分数据库都支持基于口令的身份认证,以vastbase为例,身份认证的流程如下:高权限用户创建新用户
CREATE USER u1 PASSWORD 'u1.pass1';数据库在
pg_authid系统表中存储用户以及密码的哈希SELECT oid, rolname, rolvalidbegin, rolpassword FROM pg_authid WHERE rolname = 'u1'; oid | rolname | rolvalidbegin | rolpassword -------+---------+---------------+-------------------------------------------------------------------------- 24576 | u1 | | sha2565e3b533ca5db32acdffdb6aea03395af163ac3cfdc9ddb.......数据库在
pg_auth_history系统表中存储密码创建时间SELECT roloid, passwordtime FROM pg_auth_history; oid | passwordtime -------+------------------------------- 24576 | 2025-02-11 12:17:02.969642+08新用户登录数据库
gsql -d postgres -U u1 -W 'u1.pass1' -r数据库校验新用户信息:数据库接收用户建立连接的请求时,会进行一系列身份鉴别操作,包括:检查用户提供的密码与pg_authid中的值是否匹配,检查pg_auth_history中记录的密码生成日期与当前日期是否间隔较久等
身份认证配置参数
大部分数据库都支持配置密码有效期等与密码有关的参数。比如,oracle中,控制密码有效期的参数为PASSWORD_LIFE_TIME,vastbase中,控制密码有效期的参数为password_effect_time。数据库配置参数
在vastbase中,数据库的配置参数称为GUC参数,password_effect_time是用于控制密码有效期的GUC参数,包括password_effect_time等大部分GUC参数的作用范围是整个集群,即所有用户的密码有效期都由1个GUC参数控制。
在oracle中,针对密码有效期等少部分参数,支持按用户级配置参数,即每个用户都可以配置独立的PASSWORD_LIFE_TIME参数,该功能称为profile。本文主要讨论的内容,只包含用户级配置参数。
2 GUC参数的使用方法
在opengauss中,有6个GUC参数与profile中的参数一致。
SELECT name, setting, vartype, context FROM pg_settings WHERE name in (
'failed_login_attempts',
'password_effect_time',
'password_reuse_time',
'password_reuse_max',
'password_lock_time',
'session_timeout');
name | setting | vartype | context
----------------------+---------+---------+---------
failed_login_attempts | 3 | integer | sighup
password_effect_time | 90 | real | sighup
password_lock_time | 0.0001 | real | sighup
password_reuse_max | 0 | integer | sighup
password_reuse_time | 0.0001 | real | sighup
session_timeout | 600 | integer | user
此处,先介绍各参数的功能,以及如何验证参数的功能。
一、failed_login_attempts
用户使用账号和密码登录数据库时,如果密码连续失败多次,则账号将被锁定一段时间。
failed_login_attempts用于设置出发锁定的连续失败次数的阈值。
设置参数
export DATADIR=$GAUSSHOME/data1 gs_guc reload -D $DATADIR -c "failed_login_attempts=3"创建用户
CREATE USER u1 PASSWORD 'u1.pass1';连续失败登录
gsql -d postgresql -U u1 -W '1.wrong_pass' gsql -d postgresql -U u1 -W '2.wrong_pass' gsql -d postgresql -U u1 -W '3.wrong_pass'查看失败次数
从系统表中,查看用户的失败登录次数gsql -d postgres -c " SELECT * FROM pg_user_status WHERE roloid = (SELECT oid FROM pg_authid WHERE rolname = 'u1');" roloid | failcount | locktime | rolstatus | permspace | tempspace | passwordexpired -------+-----------+-------------------------------+-----------+-----------+-----------+----------------- 16411 | 3 | 2025-02-21 12:05:10.199257+08 | 0 | 0 | 0 | 0由于密码错误次数达到限制,接下来,账号将被锁定
gsql -d postgres -U u1 -W 'u1.pass1' -r -- 预期输出 FATAL: The account has been locked. -- 解锁方法 gsql -d postgres -c "ALTER USER u1 ACCOUNT UNLOCK;"清理环境
DROP USER u1;
二、password_lock_time
用户使用账号和密码登录数据库时,如果密码连续失败多次,则账号将被锁定一段时间
password_lock_time用于设置账号锁定时间
该参数与failed_login_attempts结合使用,只能用来解锁自动锁定场景,即触发密码错误次数导致的锁定,不能解锁主动锁定场景ALTER USER .. ACCOUNT LOCK
账号被锁定后,自动解锁的时间
# 1天 = 24 * 60 * 60 = 86400秒,0.0001天是 8.64秒 export DATADIR=$GAUSSHOME/data1 gs_guc reload -D $DATADIR -c "password_lock_time=0.0001d" gs_guc reload -D $DATADIR -c "failed_login_attempts=3"创建用户
CREATE USER u1 PASSWORD 'u1@pass1';锁定用户
gsql -d postgres -c " SELECT * FROM pg_user_status WHERE roloid = (SELECT oid FROM pg_authid WHERE rolname = 'u1');" gsql -d postgres -r -U u1 -W 'u1@error' -c "SELECT 1" gsql -d postgres -r -U u1 -W 'u1@error' -c "SELECT 1" gsql -d postgres -r -U u1 -W 'u1@error' -c "SELECT 1" # 连续失败3次,账号被短暂锁定,无法登录 gsql -d postgres -r -U u1 -W 'u1@pass1' -c "SELECT 1" # 预期输出 FATAL: The account has been locked. gsql -d postgres -c " SELECT * FROM pg_user_status WHERE roloid = (SELECT oid FROM pg_authid WHERE rolname = 'u1');" # 预期输出 roloid | failcount | locktime | rolstatus | permspace | tempspace | passwordexpired --------+-----------+-------------------------------+-----------+-----------+-----------+----------------- 16477 | 3 | 2025-02-21 16:57:21.263935+08 | 1 | 0 | 0 | 0 # 等几秒钟,超过8.64秒 # 系统表中的锁定状态被自动清理 gsql -d postgres -c " SELECT * FROM pg_user_status WHERE roloid = (SELECT oid FROM pg_authid WHERE rolname = 'u1');" # 预期输出 roloid | failcount | locktime | rolstatus | permspace | tempspace | passwordexpired --------+-----------+-------------------------------+-----------+-----------+-----------+----------------- 16477 | 0 | 2025-02-21 16:57:21.263935+08 | 0 | 0 | 0 | 0 # 现在可以连接成功了 gsql -d postgres -r -U u1 -W 'u1@pass1' -c "SELECT 1" # 预期输出 连接成功
三、password_effect_time
为用户设置密码时,密码都有有效期。
password_effect_time用于设置有效期的时间。但是,在vastbaes和opengauss中,密码达到有效期之后,即密码过期后,密码仍然可以正常使用,没有任何功能上的影响。
创建用户
CREATE USER u1 PASSWORD 'u1.pass1';查看密码创建日期
SELECT roloid, passwordtime FROM pg_auth_history; oid | passwordtime ----------+------------------------------- 24576 | 2025-02-11 12:17:02.969642+08查看密码有效期
用户主动调用函数,查看当前用户的密码过期剩余天数SELECT gs_password_deadline();密码过期的表现
每次使用gsql连接数据库时,gsql会自动执行gs_password_deadline()函数,获取密码有效期。如果密钥过期,则打印一条提醒
除此之外,没有其他地方使用password_effect_time参数,即使密码过期,相关账号依然可以正常使用,而且也只是gsql会打印提醒,libpq/JDBC/ODBC等都不会打印主动让密码过期
在vastase中,主动让密码过期,与password_effect_time这个GUC参数无任何关系
用户可主动执行ALTER USER .. EXPIRED设置密码过期,此时,系统表pg_user_status中,用户对应的passwordexpired列的值将由0变为1,即代表用户密码过期ALTER USER u1 PASSWORD EXPIRED; -- 主动让密码过期后,用户无法连接数据库,也无法执行gs_password_deadline函数 gsql -d postgres -U u1 -W 'u1.pass1' -c "SELECT gs_password_deadline()" -- 输出 ERROR: Please use "ALTER ROLE user_name IDENTIFIED BY 'password' REPLACE 'old password';" to modify the expired password of user u1 before operation!清理环境
DROP USER u1;
四、 password_reuse_max
创建用户
CREATE USER u1 PASSWORD 'u1.pass1';设置GUC参数,不能重复使用最近3次使用的密码
export DATADIR=$GAUSSHOME/data1 gs_guc reload -D $DATADIR -c "password_reuse_max=3"修改密码
ALTER USER u1 PASSWORD 'u1.pass2'; ALTER USER u1 PASSWORD 'u1.pass3'; -- 重复倒数第3次使用的密码 ALTER USER u1 PASSWORD 'u1.pass1'; -- 预期输出 ERROR: The password cannot be reused. -- 再修改1次密码 ALTER USER u1 PASSWORD 'u1.pass4'; -- 重读倒是读4次使用的密码 ALTER USER u1 PASSWORD 'u1.pass1'; -- 预期输出 修改密码成功
五、password_reuse_time
确保其他GUC参数不影响测试
export DATADIR=$GAUSSHOME/data1 gs_guc reload -D $DATADIR -c "password_reuse_max=0"设置集群级GUC参数
# 1天 = 24 * 60 * 60 = 86400秒,0.0001天是 8.64秒 gs_guc reload -D $DATADIR -c "password_reuse_time=0.0001"创建用户
CREATE USER u1 PASSWORD 'u1.pass1'; ALTER USER u1 PASSWORD 'u1.pass2';查看用户曾使用过的密码
SELECT * FROM pg_auth_history WHERE roloid = (SELECT oid FROM pg_authid WHERE rolname = 'u1'); roloid | passwordtime | rolpassword --------+-------------------------------+------------------------------------ 16419 | 2025-02-21 15:20:50.308879+08 | sha256c84795e1631bbb8bf1ecf923... 16419 | 2025-02-21 15:22:06.754397+08 | sha2562939db0b3ffc71ee3115e010...使用旧密码
-- 使用不太古老的密码(确保不要超过8.64秒) ALTER USER u1 PASSWORD 'u1.pass3'; ALTER USER u1 PASSWORD 'u1.pass4'; ALTER USER u1 PASSWORD 'u1.pass3'; -- 8.64秒内快速改回pass3 -- 预期输出 ERROR: The password cannot be reused. -- 使用更古老一点的密码(确保已超过8.64秒) ALTER USER u1 PASSWORD 'u1.pass3'; -- 预期输出 修改成功清理环境
DROP USER u1;
六、session_timeout
设置回话过期时间
export DATADIR=$GAUSSHOME/data1 gs_guc reload -D $DATADIR -c "session_timeout=8s"创建用户
CREATE USER u1 PASSWORD 'u1.pass1';连接数据库
gsql -d postgres -U u1 -W 'u1.pass1' -r SELECT 1; -- 睡10秒,保证睡眠充足 SELECT 1; -- 预期输出 WARNING: Session unused timeout.opengauss与vastbase中,当用户的密码过期时,只有2个表现:
- gsql:每次使用gsql连接数据库时,gsql会自动执行
gs_password_deadline()函数,获取密码有效期。如果密钥过期,则打印一条提醒。 - 内置函数:主动调用
SELECT gs_password_deadline()函数会显示密码过期
除此之外,没有其他地方使用password_effect_time参数,即使密码过期,相关账号依然可以正常使用,只是gsql会打印一条提醒。
- gsql:每次使用gsql连接数据库时,gsql会自动执行
对照组:验证集群级guc参数password_effect_time
请参考上述2个guc参数验证方式,为节约篇幅,此处不再继续给示例
查看密码创建日期的语法如下:SELECT roloid, passwordtime FROM pg_auth_history; oid | passwordtime -------+-------------------------------opengauss和vastbase中,密码的另一种强制过期,是通过是否主动执行
ALTER USER .. EXPIRED设置的,此时,系统表pg_user_status中,用户对应的passwordexpired列的值将由0变为1,即代表用户密码过期。密码创建时间、密码有效期天数设置等,并不会导致密码真的过期。ALTER USER u1 PASSWORD EXPIRED; -- 主动让密码过期后,用户无法连接数据库,也无法执行gs_password_deadline函数 gsql -d postgres -U u1 -W 'u1.pass1' -c "SELECT gs_password_deadline()" -- 输出 ERROR: Please use "ALTER ROLE user_name IDENTIFIED BY 'password' REPLACE 'old password';" to modify the expired password of user u1 before operation!
3 pg md5
ClientAuthentication
hba_getauthmethod
case uaMD5:
CheckPWChallengeAuth
case uaPassword:
CheckPasswordAuth
sendAuthRequest
recv_password_packet
get_role_password
plain_crypt_verify
pg_md5_encrypt