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("...")
    服务端代码

      

      

      

  • 相关阅读:
    topk 问题 --转载
    MySQL是否使用外键
    MySQL的事务隔离---总结和转载
    MySQL设计规范--转自腾讯云社区
    docker图解--转载
    单点登录soo-转载
    在linux上配置后端所需的内容
    推荐一个计算机漫画地址
    python与mysql数据库连接中常见错误
    python_excel_读写(转载)
  • 原文地址:https://www.cnblogs.com/golangav/p/7265376.html
Copyright © 2011-2022 走看看