避免服务被恶意攻击,需对ip进行过滤,即短时间内限制ip的访问次数。
其中Flask框架可使用FlaskLimiter包进行处理。
Tornado框架由于没有可用的包来使用,只能自己编写过滤器。然后以注解的方式添加到到方法前。
ip过滤方法如下:
# -*- coding: utf-8 -*-
import datetime
iplist = {} # 存放访问的IP 格式 {'192.168.1.124': {'2020-12-08 17:00:33': 1}, '192.168.1.124': {'2020-12-08 17:00:33': 4}}
def authenticated_async(method):
"""
限制同ip访问次数
Args: method
Returns: method
"""
def wrapper(self, *args, **kwargs):
global iplist
# 获取ip地址
ip = self.request.remote_ip
datetimes = datetime.datetime.now()
now_time = datetimes.strftime("%Y-%m-%d %H:%M:%S") # 转化成字符串便于存储
if ip not in iplist.keys():
tmp_data = {now_time: 1}
iplist[ip] = tmp_data
method(self, *args, **kwargs)
else:
item = iplist.get(ip)
time_key_str = list(item)[0] # 取出IPList的第二层时间键
times_key = list(item.values())[0]
# 转为时间格式进行时间间隔计算
time_key = datetime.datetime.strptime(time_key_str, '%Y-%m-%d %H:%M:%S')
# print("时间格式",type(datetimes - time_key),datetimes - time_key)
# >>> 时间格式 <class 'datetime.timedelta'> 0:00:00.213644
if (datetimes - time_key).seconds == 0: # 相同时间内 则判断是否超过5次
if times_key > 5: # 同一秒访问等于或大于5 就不允许请求接口了
# 返回限制结果
ret = {'code': -1, 'msg': "Error", 'data': "访问频率过快,请稍后再访问!"}
self.set_status(401)
self.write(ret)
return
else: # 小于等于5次 则增加该IP请求次数
tmp_data = {ip: {time_key.strftime("%Y-%m-%d %H:%M:%S"): times_key + 1}}
iplist.update(tmp_data)
method(self, *args, **kwargs)
else:
tmp_data = {now_time: 1}
iplist[ip] = tmp_data
method(self, *args, **kwargs)
return wrapper
将上述方法以注解的方式添加到需要的方法前。
class MainHandler(RequestHandler):
@authenticated_async # ip拦截器
def post(self):
# 各种操作...
self.write(ret_msg)