API验证

为什么要做API验证?

传输过程中,保证数据不被篡改。

一 静态令牌

客户端

import requests
key = "abcdefg1234567890"
response = requests.get("http://127.0.0.1:8012/api/asset.html",headers={'OpenKey':key})
print(response.text)

服务端

api_key = 'abcdefg1234567890'    # 可以放置在配置文件中
def asset(request):
    if request.method == 'GET':
        client_key = request.META.get('HTTP_OPENKEY')    # 规则HTTP_大写的key
        if client_key == api_key:
            return HttpResponse('验证通过')
        else:
            return HttpResponse('验证失败')

总结:存在隐患,key值一旦被他人截取,则可验证成功

二 简易动态令牌

根据当前时间来生成动态令牌

客户端

import time
import hashlib

# 通过时间组成动态字符串
key = "abcdefg1234567890"
ctime = time.time()
new_key = '%s|%s' %(key,ctime)

m = hashlib.md5()
m.update(bytes(new_key,encoding='utf8'))
md5_key = m.hexdigest()
md5_time_key = '%s|%s' %(md5_key,ctime)

response = requests.get("http://127.0.0.1:8012/api/asset.html",headers={'OpenKey':md5_time_key})
print(response.text)

服务端

from django.shortcuts import render,HttpResponse
import hashlib
api_key = 'abcdefg1234567890'    # 可以放置在配置文件中
def asset(request):
    if request.method == 'GET':
        client_md5_time_key = request.META.get('HTTP_OPENKEY')    # 规则:HTTP_大写的key
        client_md5_key,client_time = client_md5_time_key.split('|')
        server_new_key = '%s|%s' % (api_key, client_time)
        m = hashlib.md5()
        m.update(bytes(server_new_key, encoding='utf8'))
        server_md5_key = m.hexdigest()
        if client_md5_key == server_md5_key:
            return HttpResponse('验证通过')
        else:
            return HttpResponse('验证失败')

总结:存在隐患,md5_time_key一旦被他人截取,则可验证成功

三 真正的动态令牌

思路:还是通过时间来达到动态效果,但要满足以下几点:

  • 服务端时间与客户端发送过来的时间与做比较,超时则不允许访问,比如30s
  • 服务端server_md5_key与客户端client_md5_key对比,不匹配则验证失败
  • 在服务端建立一个已访问key数据列表或字典,验证客户端发送过来的key是否存在,若存在则证明已经访问过,则不允许访问

客户端

import requests
import time
import hashlib

# 通过时间组成动态字符串
key = "abcdefg1234567890"
ctime = time.time()
new_key = '%s|%s' %(key,ctime)

m = hashlib.md5()
m.update(bytes(new_key,encoding='utf8'))
md5_key = m.hexdigest()
md5_time_key = '%s|%s' %(md5_key,ctime)

response = requests.get("http://127.0.0.1:8012/api/asset.html",headers={'OpenKey':md5_time_key})
print(response.text)

服务端

from django.shortcuts import render,HttpResponse
import hashlib
import time

timeout = 30        # 设置超时时间,可以放置在配置文件中
api_key = 'abcdefg1234567890'    # 可以放置在配置文件中
api_key_record = {
    # '21ca6c1170cba56ae8fc0dfa9e75ab2d|1522419311.9073045':1522419341.9073045
}         # 初始化存储客服端key字典

def asset(request):
    if request.method == 'GET':
        client_md5_time_key = request.META.get('HTTP_OPENKEY')    # 规则:HTTP_大写的key
        client_md5_key,client_time = client_md5_time_key.split('|')
        client_time = float(client_time)
        server_time = time.time()

        # 第一层验证--超时验证
        if server_time - client_time > timeout:
            return HttpResponse('超时,验证失败...')

        # 第二层验证--数据一致性验证
        server_new_key = '%s|%s' % (api_key, client_time)
        m = hashlib.md5()
        m.update(bytes(server_new_key, encoding='utf8'))
        server_md5_key = m.hexdigest()
        if client_md5_key != server_md5_key:
            return HttpResponse('修改数据,验证失败...')

        # 删除超时数据
        for k in list(api_key_record.keys()):
            v = api_key_record[k]
            if server_time > v:
                del api_key_record[k]

        # 第三层验证--用户验证
        if client_md5_time_key in api_key_record:
            return HttpResponse('有用户已登录,验证失败...')
        else:
            api_key_record[client_md5_time_key] = client_time + timeout
            
        return HttpResponse('验证通过')

总结:该方式借鉴了Tornado加密Cookie类似(创建动态key:md5(key+tiem)|tiem)。

四 补充

以上还存在一个风险,那就是人家的网速比我们快,获取到我们发送的数据然后在我们之前发送到服务端,该如何处理呢?

posted @ 2018-03-30 21:22  Joe1991  阅读(165)  评论(0)    收藏  举报