PostgreSQL 用户登录失败账号锁定
PostgreSQL 用户登录失败账号锁定
下载地址 https://github.com/okbob/session_exec.git
[root@localhost src]# unzip session_exec-master.zip
[root@localhost src]# cd session_exec-master/
[root@localhost session_exec-master]# make pg_config=/usr/local/pgsql-12.8/bin/pg_config
[root@localhost session_exec-master]# make pg_config=/usr/local/pgsql-12.8/bin/pg_config install
配置 postgresql
[root@localhost session_exec-master]# su - postgres
[postgres@localhost session_exec-master]$ cd /usr/local/pgsql-12.8/data/
[postgres@localhost data]$ vim postgresql.conf
session_preload_libraries='session_exec'
session_exec.login_name='login'
重启数据库
[postgres@localhost data]$ pg_ctl restart -D /usr/local/pgsql-12.8/data/
创建 t_login 表用于存储提取自数据库日志中登录失败的信息
CREATE TABLE t_login (
login_time timestamp(3) with time zone,--插入时间
user_name text,--数据库登录用户
flag int4 --标志位,0 代表过期数据,1 代表正常状态数据
);
使用 file_fdw 外部表记录数据库日志信息
如果 file_fdw 如果未配置过,参见下面步骤
CREATE extension file_fdw;
CREATE SERVER pglog FOREIGN DATA WRAPPER file_fdw;
建立外部表 postgres_log,关联数据库日志中登录失败的信息
CREATE FOREIGN TABLE postgres_log(
log_time timestamp(3) with time zone,
user_name text,
database_name text,
process_id integer,
connection_from text,
session_id text,
session_line_num bigint,
command_tag text,
session_start_time timestamp with time zone,
virtual_transaction_id text,
transaction_id bigint,
error_severity text,
sql_state_code text,
message text,
detail text,
hint text,
internal_query text,
internal_query_pos integer,
context text,
query text,
query_pos integer,
location text,
application_name text
) SERVER pglog
OPTIONS ( program 'find /usr/local/pgsql-12.8/data/log/ -type f -name 'postgresql*.csv' -mtime -1 -exec cat {} \;', format 'csv' );
创建登录函数 login
create or replace function login() returns void as $$
declare
res text;
c1 timestamp(3) with time zone;
begin
--获取当前日志中最新时间
select login_time
from public.t_login
where flag = 0
order by login_time
desc limit 1
into c1;
--将最新的数据插入 t_login 表
insert into public.t_login
select log_time,user_name
from public.postgres_log
where command_tag='authentication'
and error_severity= 'FATAL'
and log_time > c1;
update public.t_login set flag = 1 where login_time > c1;
--检查登录失败次数是否大于 3,若大于 3 则锁定用户
for res in select user_name from public.t_login where flag = 1 group by user_name having count(*) >=3
loop
--锁定用户
EXECUTE format('alter user %I nologin',res);
--断开当前被锁定用户会话
EXECUTE 'select pg_catalog.pg_terminate_backend(pid) from pg_catalog.pg_stat_activity where usename=$1' using res;
raise notice 'Account % is locked!',res;
end loop;
end;
$$ language plpgsql strict security definer set search_path to 'public';
测试
create user test_user encrypted password 'test@20220526';
模拟 test_user 用户登录失败,输入错误密码
$ psql -h 192.168.30.140 -U test_user cloud_test
Password for user test_user:
psql: error: FATAL: password authentication failed for user 'test_user'
通过外部表查看登录失败的日志
select * from postgres_log where command_tag='authentication' and error_severity= 'FATAL';
解锁用户
alter user test_user login ;
同时清空登录失败的标记位
update t_login set flag = 0 where user_name='test_user' and flag=1;