系统登录失败封禁和解禁

系统登录失败封禁和解禁
  这个需求如果换成开发去实现,很简单。但因为我们没有该系统源码,又遇上等保整改(不整改不让过等保),为了分担前端任务(据说要重新开发个伪登录页面,改各种东西适配整改任务),领导就安排我去做。今天算是完成了,一开始搞错实现逻辑,还白做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.sh
 
2、监控多个账号
   跟单账号的大同小异,需要为每个账号单独准备各自的 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次
随即收到钉钉告警:
 

 

 等30分钟后解禁即可(图就不贴了,免得啰嗦)

   洗洗睡。。。
 
posted @ 2023-04-04 23:07  windysai  阅读(89)  评论(0编辑  收藏  举报