最近,我的一个小网站被攻击了,今天跟大家讲讲是咋回事?

故事背景

我的一个小网站,部署在 4 核 8G 单机上,最近总是收到云监控报警。

查了 log 发现,我是被流量攻击了。

调研了一下云平台的安全服务,还挺贵,弃疗了。

我还是自己写吧。

实现思路

我之前的思路是配置 nginx 的黑名单,每次添加新的黑名单之后,还要重启 Nginx。

后来发现不用这么麻烦,直接用 Linux 的 iptables 防火墙,既高效又简单。连 403 都不要那些坏人看到!

我的实现思路如下:

  1. 监测 log 日志,分析访问 ip。
  2. 首先,我的小网站访问量不高。如果某个 ip 一天访问超过 10 次,我就觉得有鬼了。于是,我决定,每天 ip 的访问次数超过 100 就果断封掉。(为了避免误伤,我暂时把这个阈值设置成 100,后面看情况动态调整。)

功能拆解

  1. 编写脚本,按日期拆分 access.log(之前犯懒没做日志拆分,只是定时删除了访问日志)。
  2. 编写定时任务,每天 0 点拆分访问日志。
  3. 编写脚本,分析 access.log 访问日志,封禁当天访问次数超过 100 的 ip。
  4. 编写定时任务,每 10 分钟执行一次封禁 ip 脚本。

具体实现

1. 日志拆分脚本

具体代码如下(其中LOG_PATHPID换成你自己的路径):

# 每天0点执行日志按日期分隔脚本 0 0 * * * cd /www/Home/ && ./log_cut.sh
#!/bin/bash
#此脚本⽤于⾃动分割Nginx的⽇志,包括access.log
#每天00:00执⾏此脚本将前⼀天的access.log重命名为access-xxxx-xx-xx.log格式,并重新打开⽇志⽂件
#Nginx⽇志⽂件所在⽬录 todo 换成你自己的
LOG_PATH=/data/logs/nginx/
#获取昨天的⽇期
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)
#获取pid⽂件路径 todo 换成你自己的
PID=/var/run/nginx.pid
#分割⽇志
mv ${LOG_PATH}access.log ${LOG_PATH}access-${YESTERDAY}.log
#向Nginx主进程发送USR1信号,重新打开⽇志⽂件
kill -USR1 `cat ${PID}`

2. 编写定时任务

# 每天0点执行日志按日期分隔脚本 
0 0 * * * cd /www/Home/ && ./log_cut.sh
  • && 表示将两个命令连接在一起,先执行前面的,执行后面的。
  • 如果你不知道 crontab 的定时任务怎么编写,强烈建议你使用这个工具:「Crontab 在线工具」,使用效果如下:

3. 编写封禁 ip 脚本

注释写得很清楚了:

  • logdir替换成你自己的地址.
  • /tmp/nginx_deny.log 也可以设置成你自己的地址,或者用这个地址也可以。
# 每十分钟执行一次封禁ip脚本 */10 * * * * cd /www/Home/ && ./blackip.sh
#!/bin/bash
logdir=/data/logs/nginx/access.log #nginx访问日志文件路径
port=443
#循环遍历日志文件取出访问量大于100的ip(忽略自己本地ip)
for drop_ip in $(cat $logdir | grep -v '127.0.0.1' | awk '{print $1}' | sort | uniq -c | sort -rn | awk '{if ($1>100) print $2}'); do
# 避免重复添加
  num=$(grep ${drop_ip} /tmp/nginx_deny.log | wc -l)
if [ $num -ge 1 ]; then
continue
fi
# shellcheck disable=SC2154
  iptables -I INPUT -p tcp --dport ${port} -s ${drop_ip} -j DROP
echo ">>>>> $(date '+%Y-%m-%d %H%M%S') - 发现攻击源地址 ->  ${drop_ip} " >>/tmp/nginx_deny.log #记录log
done

4. 编写封禁 ip 定时任务

# 每十分钟执行一次封禁ip脚本 
*/10 * * * * cd /www/Home/ && ./blackip.sh

封禁效果

好了,妈妈再也不用担心我被莫名其妙地攻击了。

思考

如果自己人的 ip 不小心被封了怎么办呢?

别担心,可以用下面的命令:

#清空屏蔽IP
iptables -t filter -D INPUT -s 1.2.3.4 -j DROP

#一键清空所有规则
iptables -F

为了满足爱学习的小伙伴,附上 iptables 常用命令。

iptables 常用命令

1.清除 iptables(常用)

iptables -F

2. 备份 iptables(常用)

iptables-save > iptables.txt

3. 导入 iptables(常用)

iptables-restore 

4. 机器重启自动生效(常用)

service iptables save

5.清空某条规则

iptables -t filter -D INPUT -s 1.2.3.4 -j DROP

6. 禁止某个 ip(下面用 $ip 表示)访问本机

iptables -I INPUT -s $ip -j DROP

7. 禁止某个 ip 段(下面用 $ip/$mask 表示,其中 $mask 是掩码)访问本机

iptables -I INPUT -s $ip/$mask -j DROP

8. 禁止本机访问某个 ip(下面用 $ip 表示)

iptables -A OUTPUT -d $ip -j DROP

9. 禁止某个 ip(下面用 $ip 表示)访问本机的 80 端口的 tcp 服务

iptables -I INPUT -p tcp –dport 80 -s $ip -j DROP

10. 禁止所有 ip 访问本机的 80 端口的 tcp 服务

iptables -A INPUT -p tcp --dport 80 -j DROP

11. 禁止所有 ip 访问本机的所有端口

iptables -A INPUT -j DROP

12. 除了某个 ip(下面用 $ip 表示)之外,其他 ip 都无法访问本机的 3306 端口(常用)

(1)首先,禁止所有:

iptables -I INPUT -p tcp --dport 3306 -j DROP

(2)然后,开放个别:

iptables -I INPUT -s $ip -p tcp --dport 3306 -j ACCEPT

总结

如果你也碰到类似的问题,欢迎复刻我的经验。

如果你有更好的方案,欢迎赐教。

来源 | 程序员升职加薪之旅

作者 | 王中阳Go

分类: 工具

0 条评论

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

蜀ICP备16001794号
© 2014 - 2024 linpxing.cn All right reserved.