系统登录失败封禁和解禁
这个需求如果换成开发去实现,很简单。但因为我们没有该系统源码,又遇上等保整改(不整改不让过等保),为了分担前端任务(据说要重新开发个伪登录页面,改各种东西适配整改任务),领导就安排我去做。今天算是完成了,一开始搞错实现逻辑,还白做2小时。。。
我们先从最简单的单账号封禁和解禁去实现,再过渡到多账号。
再明确下需求:
最近30分钟内登录失败次数超过5次,禁用该账号;30分钟后解除禁用。
一、背景介绍
单账号和多账号都需要两个脚本:封禁脚本和解禁脚本。封禁脚本对时间粒度要求比较高,我弄成每2秒探测一次,解禁脚本则是每分钟跑一次。
其中
(1)对账号的封禁和解禁都是通过数据库表的字段更新去实现的(需要两个表控制)
(2)登录失败日志系统也是记录到一个数据库表上,长这个样子,这3个字段比较重要:sql需要筛选“登录失败”的日志,脚本需要日志时间和日志内容去分析
二、需求实现
1、监控一个账号:test01
封禁思路:
(1)跟进当前时间(check_time),sql查到最近30分钟内的失败登录日志(要转成时间戳进行比较),记录到文件:fail.log
(2)对fail.log进行分析,判断账号失败条数(从日志内容username='账号'截取)是否超过5次,超过则通过sql去禁止用户登录
(3)写入30分钟内最近一条的失败登录时间(fail_time)到 isdisabled.log(后面解禁账号用到)
(4)发监控,为了避免因探测次数每2次太频繁,导致告警不断发,我用了一个 alert.log 的文件,当里面写入1,代表已发过,下次不要再发;当为空,代表没有发过,则发一次告警。
脚本:
1 #!/bin/bash
2 step=2 # 每2秒跑一次,不能大于60 3 for ((i=0;i<60;i=(i+step)));do 4 5 ## 当前检测时间及对应时间戳 6 check_time=`date +"%Y-%m-%d %H:%M:%S"` 7 check_TimeStamp=`date -d "$check_time" +%s` 8 9 # 30分钟前(当前检测时间戳-1800秒)的时间及对应时间戳 10 before30_TimeStamp=`expr $check_TimeStamp - 1800` 11 before30_time=`date -d @$before30_TimeStamp +"%F %T"` 12 13 # 2、获取最近30分钟内的失败日志 14 mysql -u${登录用户} -p${登录用户密码} -h${数据库ip} -e "use 数据库名; select * from 失败日志表 where title = '登录失败' and log_time >= '$before30_time' ORDER BY log_time desc;" | grep -v "log_id" > fail.log 15 16 checkuser=test01 17 cat fail.log |awk -F'username=' '{print $2}' |awk -F ';' '{print $1}' |sort |uniq -c | sort -nr | awk '{print $0 }' > judge.file 18 19 # 3、判断该账号是否超过5次失败登录 20 num=`grep $checkuser judge.file |awk '{print $1}'` 21 22 ## 最近30分钟内, 账号失败登录超过5次 23 if [ $num -gt 5 ]; then 24 mysql -u${登录用户} -p${登录用户密码} -h${数据库ip} -e "use 数据库名; update 某表 set 账号禁用字段=1 where username='$checkuser';" 25 26 ## fail_time:最新登录失败时间 27 fail_time=`head -n1 fail.log |awk '{print $5" "$6}'` 28 echo $fail_time $checkuser "30分钟内登录失败5次,被禁用" >> isdisabled.log 29 30 ## 控制报警次数,只发一次 31 if ! test -s alert.log; then 32 echo "非空" 33 TOKEN="钉钉机器人token" 34 PHONE="我的手机号" 35 DATE=`date +%F_%H:%M:%S` 36 37 curl -H "Content-Type:application/json" -X POST --data '{"msgtype":"text","text":{"content":"当前时间:'$DATE'\nxxx系统:\n'$checkuser'被封禁(30分钟内失败次数超过5次)! "} , "at": {"atMobiles": ['${PHONE}'], "isAtAll": false}}' ${TOKEN} > /dev/null 2>&1 38 39 echo "1" > alert.log 40 fi 41 fi 42 43 sleep $step 44 done 45 exit 0
解禁思路: (1)读取 isdisabled.log文件,拿到该账号下最近一次失败登录的时间(isDisabled_DateTime),超过(diff)则调用sql 解禁账号。 (2)清空失败登录日志文件 isdisabled.log (给上面监控登录失败用) (3)清空告警次数日志文件 alert.log (给上面监控登录失败用)
1 #!/bin/bash 2 3 #判断封禁日志是否为空 4 # 非空:账号没有解禁,判断时间是否超过30分钟 5 6 if test -s isdisabled.log; then 7 #非空代表有解禁列表 8 echo "非空" 9 10 isDisabled_DateTime=`tail -n1 isdisabled.log |awk '{print $1" "$2}'` 11 isDisabled_DateTime_TimeStamp=`date -d "$isDisabled_DateTime" +%s` 12 13 ## 当前检测时间及时间戳 14 check_time=`date +"%Y-%m-%d %H:%M:%S"` 15 check_TimeStamp=`date -d "$check_time" +%s` 16 17 ## 1800秒=30分钟 18 basic=1800 19 diff=`expr $check_TimeStamp - $isDisabled_DateTime_TimeStamp` 20 if [ $diff-ge $basic ]; then 21 checkuser=test01 22 mysql -u${登录用户} -p${登录用户密码} -h${数据库ip} -e "use 数据库名; update 某表 set 账号禁用字段=0 where username='$checkuser';" 23 24 #解禁后清空失败登录日志文件 25 cat /dev/null > isdisabled.log 26 27 #解禁后也清掉告警次数日志 28 cat /dev/null > alert.log 29 30 #测试 31 TOKEN="钉钉机器人token" 32 PHONE="我的手机号" 33 DATE=`date +%F_%H:%M:%S` 34 35 curl -H "Content-Type:application/json" -X POST --data '{"msgtype":"text","text":{"content":"当前时间:'$DATE'\nxxx系统:\n'$checkuser'已解禁(已封禁超过30分钟)! "} , "at": {"atMobiles": ['${PHONE}'], "isAtAll": false}}' ${TOKEN} > /dev/null 2>&1 36 37 fi 38 39 else 40 #不存在需要解封的账号, 退出 41 echo "为空" 42 exit 1 43 fi
写入到cron定时任务如下
* * * * * /bin/bash is_disabled.sh */1 * * * * /bin/bash enabled.sh2、监控多个账号 跟单账号的大同小异,需要为每个账号单独准备各自的 isdisabled.log 和 alert.log。所有账号共用一个30分钟内失败登录日志:fail.log (1)封禁脚本 for checkuser in 账号1 账号2 账号3 ; do
。。。 mysql -u${登录用户} -p${登录用户密码} -h${数据库ip} -e "use 数据库名; select * from 失败日志表 where title = '登录失败' and log_time >= '$before30_time' ORDER BY log_time desc;" | grep -v "log_id" > fail.log for checkuser in 账号1 账号2 账号3 xxx; do ## 登录失败用户及登录失败次数 cat fail.log |awk -F'username=' '{print $2}' |awk -F ';' '{print $1}' |sort |uniq -c | sort -nr | awk '{print $0 }' > judge.file 。。。 ## fail_time:最新登录失败时间 fail_time=`grep -m1 "$checkuser" fail.log |awk '{print $5" "$6}'` echo $fail_time $checkuser "30分钟内登录失败5次,被禁用" >> isdisabled.log_${checkuser} 报警 echo "1" > alert.log_${checkuser} 。。。
特意提下为什么会有个“grep -m1”,是用来匹配失败登录日志fail.log下(这个log日志),被检测账号最新的一条失败登录时间
(参考 返回第一次匹配的行:https://blog.csdn.net/a8131357leo/article/details/82945632)
(2)解禁脚本 读取各自账号下的 isdisabled.log_${checkuser} 即可。 3、效果图
在今天 15:11 到 15:20 我模拟两个账号登录系统,都失败6次 test02 6次 test333 6次
![](/i/l/?n=23&i=blog/520218/202304/520218-20230404230424198-1881699707.png)
![](/i/l/?n=23&i=blog/520218/202304/520218-20230404230514450-1125215156.png)
等30分钟后解禁即可(图就不贴了,免得啰嗦)
洗洗睡。。。 标签:封禁,checkuser,log,登录,账号,解禁,失败,fail From: https://www.cnblogs.com/windysai/p/17286715.html