标签:api 过期 xxx col lis 字符 字典 UNC 设置
第一步 携带key的请求
客户端发送http请求访问API时,在请求头里设置一个双方约定好的key, 其实没有什么卵用,请求头很容易抓包抓到
在请求头中设定key的时候,不能在key值中插入‘_’,因为django不识别‘_’,所以只能用‘-’来替代下划线,比如,客户端 的请求头‘auth-api‘:xxxxxx会被服务端自动转换成 ‘HTTP_AUTH_API‘:xxxxxxx格式
在服务器中获取使用clent_key=request.META.get(‘HTTP_AUTH_API‘)
客户端
import requests key=‘sssdkjrjefjewfakfhkj‘ respose=requests.get(url=‘http://127.0.0.1:8000/test.html/‘,headers={‘auth-api‘:key}).text #如果给Django程序发送请求头,如果headers里面的内容使用下滑杠 _,Django会不认识; #auth-api -----> 转换成 ‘HTTP_AUTH_API‘格式 #服务端获取clent_key=request.META.get(‘HTTP_AUTH_API‘) print(respose)
服务器
def test(request): key=‘sssdkjrjefjewfakfhkj‘ clent_key=request.META.get(‘HTTP_AUTH_API‘) if clent_key == key: return HttpResponse(‘你得到我了‘) else: return HttpResponse(‘休想‘)
这种策略不具备动态性,很容易被抓包抓到,黑客们只需要带着你的url再发一次就好了,所以我们先引出第二部,发送动态的url
第二步 携带key的动态url请求
首先来考虑如何实现动态性,不管是你的用户名还是密码,还有约定好的key值都不可能去动态改变,那剩下的也就只有时间戳了,很多时候我们都利用时间戳的唯一性去定制一些东西。
如果我们把key+时间戳合并再进行MD5加密成aaaaaaaa,再携带时间戳,以aaaaa|时间戳的形式放在请求头传递
服务器端我们先把摘取到时间戳,然后对key+时间进行MD5加密,然后和传递来的密文进行比对。
这样一来,好像还是毫无卵用,依然可以被获取到。。。
客户端
import requests import time import hashlib key=‘sssdkjrjefjewfakfhkj‘ ctime=str(time.time()) def MD5(arg): hs=hashlib.md5() hs.update(arg.encode(‘utf-8‘)) #python3加密使用字节类型 return hs.hexdigest() new_key=‘%s|%s‘ % (key,ctime) # sssdkjrjefjewfakfhkj | 时间戳 md5_str=MD5(new_key) auth_api_val=‘%s|%s‘%(md5_str,ctime) #d0e0ca7d1f8f72d60715696d4baac3b2(key和时间戳加密后的结果)| 时间戳 print(md5_str) respose=requests.get(url=‘http://127.0.0.1:8000/test.html/‘,headers={‘auth-api‘:auth_api_val}).text print(respose)
服务端
import hashlib import time def MD5(arg): hs = hashlib.md5() hs.update(arg.encode(‘utf-8‘)) # python3加密使用字节类型 return hs.hexdigest() def test(request): key=‘sssdkjrjefjewfakfhkj‘ auth_api_val=request.META.get(‘HTTP_AUTH_API‘) #052dd27c130f4b9b5a8a4ec4b243962d | 1507374976.4620001 client_md5_str,client_ctime =auth_api_val.split(‘|‘,maxsplit=1) server_md5_str=MD5(‘%s|%s‘%(key,client_ctime)) if client_md5_str== server_md5_str: return HttpResponse(‘你得到我了‘) else: return HttpResponse(‘休想‘)
第三步 过滤掉已经访问的url
仔细一想我们的动态url已经具备了唯一性,任凭黑客多么牛逼也不可能反解MD5值拿到key值,所以我们只需要记录一下已经访问过的url。
即使不幸被黑客获取到url,也没关系,因为他拿到的url已经被我们记录过了,变成一次性的啦。
但是如果访问量非常大的话,我们在后台维护的表单太过于庞大了,所以我们提出第四种方案来解决这个问题。
第四步 最终幻想
现在存在的问题只有数据库过于庞大的问题,如果我们可以定期清理数据库那不就好了嘛。
因此我们可以设计一个expire_time,也就是有效时间,其实越短越好,因为正常每次用户访问都是一个唯一的url
我们取到最近客户端发来的时间戳,然后减去有效时间,如果没有过期的话允许访问,已经过期的话,则拒绝。
至于删除表格数据可以设定一个可以长一点的周期,避免因监控表单而带来的性能损耗
客户端
import requests import time import hashlib key=‘sssdkjrjefjewfakfhkj‘ ctime=str(time.time()) def MD5(arg): hs=hashlib.md5() hs.update(arg.encode(‘utf-8‘)) #python3加密使用字节类型 return hs.hexdigest() new_key=‘%s|%s‘ % (key,ctime) # sssdkjrjefjewfakfhkj | 时间戳 md5_str=MD5(new_key) auth_api_val=‘%s|%s‘%(md5_str,ctime) #d0e0ca7d1f8f72d60715696d4baac3b2(key和时间戳加密后的结果)| 时间戳 print(md5_str) respose=requests.get(url=‘http://127.0.0.1:8000/test.html/‘,headers={‘auth-api‘:auth_api_val}).text print(respose)
服务端
#api验证装饰器 def api_auth(func): def inner(request,*args,**kwargs): server_float_ctime = time.time() key = ‘sssdkjrjefjewfakfhkj‘ auth_api_val = request.META.get(‘HTTP_AUTH_API‘) # 052dd27c130f4b9b5a8a4ec4b243962d | 1507374976.4620001 client_md5_str, client_ctime = auth_api_val.split(‘|‘, maxsplit=1) client_float_ctime = float(client_ctime) # 第1关时间限制 if client_float_ctime + 5 < server_float_ctime: return HttpResponse(‘想要破解密码最在5秒之内‘) # 第二关 MD5加密 server_md5_str = MD5(‘%s|%s‘ % (key, client_ctime)) if client_md5_str != server_md5_str: return HttpResponse(‘休想‘) # 第三关 for k in list(visited_keys.keys()): #清空字典访问记录 v=visited_keys[k] if server_float_ctime > v: del visited_keys[k] #已经使用过 MD5加密字符串(访问记录) if visited_keys.get(client_md5_str): return HttpResponse(‘你放弃吧‘) visited_keys[client_md5_str] = client_float_ctime+5#(只需维护5秒之内访问记录即可,因为超过5秒第一关都过不去了) return func(request,*args,**kwargs) return inner
标签:api 过期 xxx col lis 字符 字典 UNC 设置
原文地址:https://www.cnblogs.com/yangziyao/p/9427713.html