zoukankan      html  css  js  c++  java
  • API验证

    API验证

    API验证:
    	a. 发令牌: 静态
    		PS: 隐患 key被别人获取
    	b. 动态令牌
    		PS: (问题越严重)用户生成的每个令牌被黑客获取到,都会破解
    	c. 高级版本
    		PS: 黑客网速快,会窃取, so要对数据加密
    	d. 终极版本
    
    
    特点:
       为什么要用API ?
           - 数据在传输过程中,保证数据安全
       你是如何设计的 ?
    	   - Tornado 中的加密Cookie类似
    	   - 创建动态key  md5(key + time)|time (Tornado中也是这么做)
    	   - 限制
    	   	 - 第一关: 时间
    	   	 - 第二关: 算法规则
    	   	 - 第三关: 已访问的记录
    	   PS: 黑客网速快,会窃取, so要对数据加密

    a. 客户端和服务端都有一个相同的key

    客户端把key发给服务端,服务端拿着自己的key和客户端的key做比较
    
    ###客户端
    
    import time
    import requests
    
    key = "asdfasdfasdfasdf098712sdfs"
    
    response = requests.get("http://127.0.0.1:8000/api/asset.html",headers={'OpenKey':key})
    print(response.text)
    
    
    ###服务端
    
    #print(request.META)
    key = request.META.get("HTTP_OPENKEY")
    if key != settings.AUTH_KEY:
        return HttpResponse("验证失败")
    

    b. key和时间

    #客户端和服务端都有一个相同的key
    #客户端把加密key和当前时间发给服务端,服务端收到后把客户端发来的时间和自己的key加密
    #然后把加密后的字串和客户端的字串比较
     
    #客户端
     
        import time
        import requests
        import hashlib
     
        ctime = time.time()
        key = "asdfasdfasdfasdf098712sdfs"
        new_key = "%s|%s" %(key,ctime,)
     
        m = hashlib.md5()
        m.update(bytes(new_key,encoding='utf-8'))  #里面是字节数据
        md5_key = m.hexdigest()                    #返回值是字符串类型
     
        md5_time_key = "%s|%s" %(md5_key,ctime)
     
     
        response = requests.get("http://127.0.0.1:8000/api/asset.html",headers={'OpenKey':md5_time_key})
        print(response.text)
     
    #服务端
        client_md5_time_key = request.META.get("HTTP_OPENKEY")
     
        client_md5_key,client_ctime = client_md5_time_key.split("|")
     
        temp = "%s|%s"%(settings.AUTH_KEY,client_ctime)
        m = hashlib.md5()
        m.update(bytes(temp, encoding='utf-8'))
        server_md5_key = m.hexdigest()
     
     
        if server_md5_key != client_md5_key:
            return HttpResponse("验证失败")

    c. 高级版本 

    #客户端和服务端都有一个相同的key
    #客户端把加密key和当前时间发给服务端
    #服务端验证:
        #1)服务端判断服务器当前的时间是否比客户端时间快10s,如果在10s内通过,有效的杜绝了案例二成千上万的key
        #2)服务器获取客户端时间和自己key加密然后和 客户端获取到的key比较
        #3)删除与现在时间相差10s的数据(之后用memcache,redis)
        #3)在字典里判断是否有这个key,如果有不通过,没有加入字典(之后用memcache,redis)
     
     
     
    #客户端
        import time
        import requests
        import hashlib
     
        ctime = time.time()
        key = "asdfasdfasdfasdf098712sdfs"
        new_key = "%s|%s" %(key,ctime,)
     
        m = hashlib.md5()
        m.update(bytes(new_key,encoding='utf-8'))  #里面是字节数据
        md5_key = m.hexdigest()                    #返回值是字符串类型
     
        md5_time_key = "%s|%s" %(md5_key,ctime)
     
        print(md5_time_key)
        response = requests.get("http://127.0.0.1:8000/api/asset.html",headers={'OpenKey':md5_time_key})
     
        #黑客获取调用
        #response = requests.get("http://127.0.0.1:8000/api/asset.html",headers={'OpenKey':"f610077a7001c53b5a74868c5544b388|1501514254.455578"})
        print(response.text)
     
     
    #服务端
        api_key_record ={
        "76942d662d98ebe3b920a7b791bf5040|1501510243.92804":1501510243.92804,
        }
     
     
    def asset(request):
     
     
        client_md5_time_key = request.META.get("HTTP_OPENKEY")
     
        client_md5_key,client_ctime = client_md5_time_key.split("|")
        client_ctime = float(client_ctime)
        server_ctime = time.time()
     
        #第一关 时间关
        if server_ctime - client_ctime > 10:
            return HttpResponse("第一关  小伙子,别虎我,太长了")
     
        #第二关 客户端时间和服务端key加密和 客户端的密钥对比
        temp = "%s|%s"%(settings.AUTH_KEY,client_ctime)
        m = hashlib.md5()
        m.update(bytes(temp, encoding='utf-8'))
        server_md5_key = m.hexdigest()
        if server_md5_key != client_md5_key:
            return HttpResponse("第二关   规则正确")
     
     
        #以后基于memcache,目前先写入内存删除超过10s的值
        for k in list(api_key_record.keys()):
            v = api_key_record[k]
            if server_ctime > v:
                del api_key_record[k]
     
     
        #第三关 判断字典里是否有之前访问的key,如果有不通过,没有加入字典
        if client_md5_time_key in api_key_record:
            return HttpResponse("第三关  已经有人来过了")
        else:
            api_key_record[client_md5_time_key] = client_ctime + 10

    d. 终极版本

    注意: key 是从配置文件获取的
    
    装饰器要返回Httpresponse对象
    __author__ = 'Administrator'
    from Crypto.Cipher import AES
    from lib.conf.config import settings
    def encrypt(message):
        """
        数据加密
        :param message:
        :return:
        """
        key = settings.DATA_KEY
        cipher = AES.new(key, AES.MODE_CBC, key)
        ba_data = bytearray(message,encoding='utf-8')
        v1 = len(ba_data)
        v2 = v1 % 16
        if v2 == 0:
            v3 = 16
        else:
            v3 = 16 - v2
        for i in range(v3):
            ba_data.append(v3)
        final_data = ba_data.decode('utf-8')
        msg = cipher.encrypt(final_data) # 要加密的字符串,必须是16个字节或16个字节的倍数
        return msg
    
    def decrypt(msg):
        """
        数据解密
        :param message:
        :return:
        """
        from Crypto.Cipher import AES
        key = settings.DATA_KEY
        cipher = AES.new(key, AES.MODE_CBC, key)
        result = cipher.decrypt(msg) # result = b'xe8xa6x81xe5x8axa0xe5xafx86xe5x8axa0xe5xafx86xe5x8axa0sdfsd									'
        data = result[0:-result[-1]]
        return str(data,encoding='utf-8')
    
    
    def auth():
        """
        API验证
        :return:
        """
        import time
        import requests
        import hashlib
    
        ctime = time.time()
        key = "asdfasdfasdfasdf098712sdfs"
        new_key = "%s|%s" %(key,ctime,)
    
        m = hashlib.md5()
        m.update(bytes(new_key,encoding='utf-8'))  #里面是字节数据
        md5_key = m.hexdigest()                    #返回值是字符窜类型
    
        md5_time_key = "%s|%s" %(md5_key,ctime)
    
        return md5_time_key
    lib/utils.py
    from Crypto.Cipher import AES
    import requests
    import json
    from lib.utils import encrypt
    from lib.utils import auth
    
    #对数据加密字典
    v1 = encrypt(json.dumps({"k1":"v1"}))      #获取的是加密后的字节
    print(v1)
    
    response = requests.post(
        url="http://127.0.0.1:8000/api/asset.html",
        headers={'OpenKey':auth(),'content-type':'application/json'},
        data=v1
    )
    
    
    print(response.text)
    客户端调用
    import json
    import hashlib
    from django.shortcuts import render,HttpResponse
    from repository import models
    from django.conf import settings
    from api.service import PluginManager
    import time
    import json
    from Crypto.Cipher import AES
    
    
    api_key_record ={
        "76942d662d98ebe3b920a7b791bf5040|1501510243.92804":1501510243.92804,
    }
    
    
    def decrypt(msg):
        key = b'dfdsdfsasdfdsdfs'
        cipher = AES.new(key, AES.MODE_CBC, key)
        result = cipher.decrypt(msg)  # 把加密后的字节解密成不加密的字节
        data = result[0:-result[-1]]
        return str(data, encoding='utf-8')
    
    
    def outer(func):
        def wrapper(request):
            client_md5_time_key = request.META.get("HTTP_OPENKEY")
    
            client_md5_key, client_ctime = client_md5_time_key.split("|")
            client_ctime = float(client_ctime)
            server_ctime = time.time()
    
            # 第一关 时间关
            if server_ctime - client_ctime > 30:
                return HttpResponse("第一关  小伙子,别虎我,太长了")
    
            # 第二关 客户端时间和服务端key加密和 客户端的密钥对比
            temp = "%s|%s" % (settings.AUTH_KEY, client_ctime)
            m = hashlib.md5()
            m.update(bytes(temp, encoding='utf-8'))
            server_md5_key = m.hexdigest()
            if server_md5_key != client_md5_key:
                return HttpResponse("第二关   规则正确")
    
            # 以后基于memcache,目前先写入内存删除超过10s的值
            for k in list(api_key_record.keys()):
                v = api_key_record[k]
                if server_ctime > v:
                    del api_key_record[k]
    
            # 第三关 判断字典里是否有之前访问的key,如果有不通过,没有加入字典
            if client_md5_time_key in api_key_record:
                return HttpResponse("第三关  已经有人来过了")
            else:
                api_key_record[client_md5_time_key] = client_ctime + 10
                obj = func(request)
                return obj
    
        return wrapper
    
    
    
    @outer
    def asset(request):
    
    
        if request.method == 'GET':
            ys = '重要的不能被闲杂人等看的数据'
            return HttpResponse(ys)
    
        elif request.method == 'POST':
    
            server_info = decrypt(request.body)
            server_info = json.loads(server_info)
    
    
    
            # # 新资产信息
            # server_info = json.loads(request.body.decode('utf-8'))
            hostname = server_info['basic']['data']['hostname']
            # 老资产信息
            server_obj = models.Server.objects.filter(hostname=hostname).first()
            if not server_obj:
                return HttpResponse('当前主机名在资产中未录入')
    
    
            PluginManager(server_info,server_obj,hostname).exec_plugin()
    
            return HttpResponse("...")
    服务端代码

      

      

      

  • 相关阅读:
    RecyclerView 数据刷新的几种方式 局部刷新 notify MD
    【图片】批量获取几万张图片
    RV BaseRecyclerViewAdapterHelper 总结 MD
    RecyclerView.ItemDecoration 间隔线
    Kotlin【简介】Android开发 配置 扩展
    Kotlin 特性 语法糖 优势 扩展 高阶 MD
    一个十分简洁实用的MD风格的UI主框架
    折叠伸缩工具栏 CollapsingToolbarLayout
    FloatingActionButton FAB 悬浮按钮
    Glide Picasso Fresco UIL 图片框架 缓存 MD
  • 原文地址:https://www.cnblogs.com/golangav/p/7265376.html
Copyright © 2011-2022 走看看