API验证策略

第一步  携带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

 

转载于:https://www.cnblogs.com/yangziyao/p/9427713.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值