zoukankan      html  css  js  c++  java
  • Python API简单验证

    前言

    因为CMDB内部的需求,需要一个API进行数据传输,用来传递需要抓取的服务端信息信息给抓取的autoclient,autoclient抓取好之后再通过API传输到服务器,保存到数据库。但是为了防止恶意的API访问,需要做一个验证。

    设想一

    可以在客户端跟服务端都规定好一串随机字符串做验证,只有当带着这串验证的请求发送过来的时候,才让其进行访问。

    如果学过了爬虫,大家很容易就发现,这串随机字符串在浏览器里面是可以监听的,多观察几次总是会发现的。而且无论通过如何的方式,只要暴露在外面,都是会被察觉的。此时,就需要对其进行加密。

     

    设想二

    既然随机字符串在web传输中是明文状态,那我们试着将其转换成密文的,转换下思路,如果每次的请求都是随机字符串配合一串一直变动的值进行md5加密,此时,产生的验证字符串也应该变成动态密文。用什么做动态字符串来配合约定好的字符串进行md5加密呢?既然是动态的,时间戳,是最好的选择。   

    此时一切看着都很完美,但是,忽略了一点,无论是不是加密的字符串,http请求的时候都是可以监听到的,所以即使加密,即使不知道怎么加密的,依旧可以直接拿着这串字符串直接进行验证访问。尴尬。。。

    设想三

    其实上面的设想二已经做到了动态,思路上只要改一点就立刻变成可行的了。在http请求的时候,即使是在相当糟糕的网络环境里,也不会需要发送非常长的时间,因此,卡住时间便可以实现。

    在拿到client的时间戳是,服务器段只需要跟当前时间戳进行比对,如果时间间隔小于10秒就当作正常访问。就可以了。

    上面的设计思路完美的解决了动态的问题,此时不免还有疑问,如果真的会在10s内盗取到字符串直接访问呢?

    完善思路

    基于上面的问题,可以再多加异步验证,写一个列表,访问过的字符串都放在列表里,后面的访问都跟此列表比对下,如果在此列表内,就拒绝访问。

    如上的设计思路就可以解决问题。

    优化

    最后的设计思路肯定能解决问题,但是也存在一个问题,就是,随着时间进度的推移,访问列表一定会越来越大,始终是不友好的一点。肯定需要给字符串设计一个超时时间。

    visited_list = ['28g12b12128912e2kj|127381237812391', '829312g12be120e102ej12je91|12312984123123',....]

    如果以上述的方式取跟系统时间比较当然是一件很费事的工作,占用很多的IO,可以使用redis来轻松实现这个功能。

     CBV通过此类装饰方式实现验证

     验证代码

    def api_auth_method(request):
        auth_key = request.META.get('HTTP_AUTH_KEY')
        if not auth_key:
            return False
        sp = auth_key.split('|')
        if len(sp) != 2:
            return False
        encrypt, timestamp = sp
        timestamp = float(timestamp)
        limit_timestamp = time.time() - ASSET_AUTH_TIME
        print(limit_timestamp, timestamp)
        if limit_timestamp > timestamp:
            return False
        ha = hashlib.md5(ASSET_AUTH_KEY.encode('utf-8'))
        ha.update(bytes("%s|%f" % (ASSET_AUTH_KEY, timestamp), encoding='utf-8'))
        result = ha.hexdigest()
        print(result, encrypt)
        if encrypt != result:
            return False
    
        exist = False
        del_keys = []
        for k, v in enumerate(ENCRYPT_LIST):
            print(k, v)
            m = v['time']
            n = v['encrypt']
            if m < limit_timestamp:
                del_keys.append(k)
                continue
            if n == encrypt:
                exist = True
        for k in del_keys:
            del ENCRYPT_LIST[k]
    
        if exist:
            return False
        ENCRYPT_LIST.append({'encrypt': encrypt, 'time': timestamp})
        return True
    
    
    def api_auth(func):
        def inner(request, *args, **kwargs):
            if not api_auth_method(request):
                return JsonResponse({'code': 1001, 'message': 'API授权失败'}, json_dumps_params={'ensure_ascii': False})
            return func(request, *args, **kwargs)
    
        return inner
    auth
  • 相关阅读:
    Spring MVC程序中得到静态资源文件css,js,图片文件的路径问题总结
    【转】MySQL数据丢失讨论
    【摘】 pt-query-digest工具一解
    【摘】Mysql备份还原数据库之mysqldump实例及参数详细说明
    【原】redis插件安装
    【摘】linux中fstab解说
    【原】mysql慢日志分析
    【原】带宽、流量单位换算关系
    【转】Linux查看内存大小和插槽
    【转】bind
  • 原文地址:https://www.cnblogs.com/wuzdandz/p/9429784.html
Copyright © 2011-2022 走看看