CMDB API验证

为什么做API验证

API验证是防止数据在传输的过程中,保证数据不被篡改

如何设计的API验证

灵感来源于Torando中加密Cookie的源码,主要是生成加密的随机字符串。

MD5(key+time)|time 就是把秘钥和客户端的当前时间通过MD5进行加密,同时把当前时间发送到API

然后自己在服务端设计了三关验证的设计:

  • 时间,
  • 算法规则,验证密文
  • 已访问的记录

想API获取数据的时候,需要进行验证是否是合法的请求,为了达到这一目的,采用的基础方案是在装机的时候在服务器中和客户端中都保存一份秘钥,客户端想要获取数据的时候需要携带秘钥过来,GET请求的时候通过请求头发送。

API验证之字符串+请求头

客户端向API发送GET请求的时候可以在请求有中加数据,是字典的格式headers={},在Django中,自己定义的请求头发送过去后,会转换成大写,并在前面加上HTTP_。

客户端,header中的OpenKey中间不能有下划线,否则后台接收不到

import requests

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

服务端接收数据中获取请求头的中的内容,通过request.MEAT可以获取全部的请求信息,是一个字典类型。

def asset(request):
for k, v in request.META.items():
print(k, v)
if request.method == "GET":
aaa = "重要的数据"
return HttpResponse(aaa)

HTTP_OPENKEY sdflajskldf9asfdalsdf9sdgsdgs55523asdf

当客户端发送数据的请求头中没有和服务端的key匹配的时候,不通过验证

    key = request.META.get('HTTP_OPENKEY')
if settings.AUTH_KEY != key:
return HttpResponse('不能通过验证') if request.method == "GET":
aaa = "重要的数据"
return HttpResponse(aaa)

动态令牌

上面的是静态的,当网络请求被截获后,别人就可以可以利用这个漏洞。需要改良成动态的令牌,每次访问的时候客户端发送不同的随机字符串并进行加密。要动态用当前时间,或者是UUID

  • 利用当前时间和key形成动态的随机字符串
  • 通过MD5进行加密
  • 把当前时间发送到API,API利用这个时间进行MD5加密,然后比较密文

客户端

import requests
import time
import hashlib ctime = time.time()
key = 'sdflajskldf9asfdalsdf9sdgsdgs55523asdf'
new_key= '%s|%s'%(key,ctime) m = hashlib.md5()
m.update(bytes(new_key,encoding='utf8')) # python3中是字节
md5_key = m.hexdigest() # 加密后是字符串 md5_key_time = '%s|%s'%(md5_key,ctime) # 把当前时间发送后API,API利用时间进行加密,最后比较的是密文 response = requests.get("http://127.0.0.1:8000/api/asset.html", headers={'OpenKey': md5_key_time})
print(response.text)

服务端

  • 服务端接收到客户端发送的数据中包含MD5和客户端用于加密的时间
  • 服务端利用客户端发送过来的时间进行MD5加密
  • 客户端和服务端进行密文的验证
def asset(request):

    client_md5_citme = request.META.get('HTTP_OPENKEY') # 客户端发送过来的MD5和用于加密的时间
# print(client_md5_citme)
client_md5_key,client_time = client_md5_citme.split('|') # 进行分割 temp = '%s|%s'%(settings.AUTH_KEY,client_time)
m = hashlib.md5()
m.update(bytes(temp, encoding='utf8'))
server_md5_key = m.hexdigest() # 服务端利用客户端发送的时间进行MD5加密的数据 if server_md5_key!= client_md5_key:
return HttpResponse('不能通过验证') if request.method == "GET":
aaa = "重要的数据"
return HttpResponse(aaa)

API三关验证

上面存在的问题,当被加密的md5_key_time别截获任意一个后(有成千上万个),别人在任何时候都能发送请求,服务端都能返回真实数据,这是一个很大的问题。

解决方案:

  • 时间,服务端时间和客户端发送过来的时间进行比较,超过10s后,认为失效
  • 在服务端维护一个已访问列表,仅仅是10s内的,超过后删除,如果有同样的再次访问的话,认为是被被人获取的,不通过验证

第一关:时间

  • 在服务端进行判断,如果发送过来的客户端的时间和当前时间比,超过10s后,排除

服务端

def asset(request):

    client_md5_citme = request.META.get('HTTP_OPENKEY') # 客户端发送过来的MD5和用于加密的时间
# print(client_md5_citme)
client_md5_key,client_time = client_md5_citme.split('|') # 进行分割 temp = '%s|%s'%(settings.AUTH_KEY,client_time)
m = hashlib.md5()
m.update(bytes(temp, encoding='utf8'))
server_md5_key = m.hexdigest() # 服务端利用客户端发送的时间进行MD5加密的数据
client_time = float(client_time) # 把字符串类型的转化成数字
server_time = time.time() if server_time - client_time > 10:
return HttpResponse("小伙子,超时了")

客户端

客户端能正常发送,如果在10s内,客户端发送的秘钥被获取,并在10s内被请求,也是可以通过的

下面的key是黑客获取的秘钥,并在10s中内向API发送请求,同样是可以获取到数据的

import requests

key = '582d3d4bd95997954f70ae6906732de3|1501941968.090018'
response = requests.get("http://127.0.0.1:8000/api/asset.html", headers={'OpenKey': key})
print(response.text)

第二关:验证规则

这里就是在服务端进行MD5的验证

第三关: 建立已经访问的列表

如果是只采用时间的话,是有缺陷的,所以通过建立一个已经访问的列表进行进一步限制。即便是黑客获取了秘钥,当黑客发送请求的时候就能阻止黑客的请求

  • 在全局建立已经访问过的列表,这里采用字典的形式,key是客户端发送过来的密钥,value是超时时间
  • 后期使用redis memcache可以直接设置超时时间后自动回删除,这里是存在内存中,自己通过判断进行删除
# 在全局(存在内存中)建立已访问列表,格式是{'key秘钥|时间':超时时间} 后期可以用redis memcache等直接设置超时时间
api_key_record = { }
# 在进入第三关之前删除api_key_record中的超时的值
# 字典不能通过for循环中删除
for k in list(api_key_record.keys()): # 需要把字典的keys()转换成列表
v = api_key_record[k]
if server_time > v:
del api_key_record[k] # 如果超时,则删除api_key_record中相应的记录 # 第三关:建立访问列表(全局)
if client_md5_citme in api_key_record:
return HttpResponse('第三关没有通过验证')
else:
api_key_record[client_md5_citme] = client_time + 10 # 设置超时时间 10s后超时

关于字典删除的补充

字典、列表在for循环的过程中是不同删除的,在for循环的时候,就已经建立了需要遍历的数据,在循环中删除,就没法迭代了

例如:

下面的程序会报错:RuntimeError: dictionary changed size during iteration

# 字典 列表等在循环的时候不能删除
api_dict = {'k1':'v1','k2':'v2','k3':'v3'}
for k,v in api_dict.items():
if v == 'v2':
del api_dict[k] # RuntimeError: dictionary changed size during iteration

解决方法:

  • deepcopy
  • list(api_dict.keys())
  • 看下面的输出结果可知字典的keys()得到的是字典一个一种列表,通过list转换成列表
  • 循环获取字典中的value进行比较,然后进行删除
api_dict = {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
print(api_dict.keys()) # dict_keys(['k1', 'k2', 'k3'])
print(list(api_dict.keys())) # 通过list转换成列表
for k in list(api_dict.keys()):
v = api_dict[k] # 获取字典中所有的值value
if v == 'v2':
del api_dict[k]
print(api_dict)

结果:

dict_keys(['k1', 'k2', 'k3'])
['k1', 'k2', 'k3']
{'k1': 'v1', 'k3': 'v3'}

API三关验证总结

流程:

客户端和服务端中都存放一份相同的随机字符串,客户端发请求的时候把随机字符串和当前时间进行MD5加密,同时带着当前时间通过请求头发送到API,进入三关验证。

  • 第一关是时间验证 (验证服务器当前时间和客户端发送过来的时间,超过10s后,验证不通过)
  • 第二关是MD5规则验证(服务端把自己的密钥同客户端发送过来的时间进行MD5加密,进行密文的比较)
  • 第三关是访问列表验证(从访问列表中查询是否存在,如果存在,验证不通过,否则把当前值存到列表中,并设置超时时间),这里的时间可以设置成2S
# 在全局(存在内存中)建立已访问列表,格式是{'key秘钥|时间':超时时间} 后期可以用redis memcache等直接设置超时时间
api_key_record = { } def asset(request): client_md5_citme = request.META.get('HTTP_OPENKEY') # 客户端发送过来的MD5和用于加密的时间
# print(client_md5_citme)
client_md5_key,client_time = client_md5_citme.split('|') # 进行分割 # 第一关:时间验证
client_time = float(client_time) # 把字符串类型的转化成数字
server_time = time.time() if server_time - client_time > 10:
return HttpResponse("小伙子,超时了,第一关没有通过验证") # 第二关:规则验证
temp = '%s|%s'%(settings.AUTH_KEY,client_time)
m = hashlib.md5()
m.update(bytes(temp, encoding='utf8'))
server_md5_key = m.hexdigest() # 服务端利用客户端发送的时间进行MD5加密的数据 if server_md5_key!= client_md5_key:
return HttpResponse('第二关没有通过验证') # 在进入第三关之前删除api_key_record中的超时的值
# 字典不能通过for循环中删除
for k in list(api_key_record.keys()): # 需要把字典的keys()转换成列表
v = api_key_record[k]
if server_time > v:
del api_key_record[k] # 如果超时,则删除api_key_record中相应的记录 # 第三关:建立访问列表(全局)
if client_md5_citme in api_key_record:
return HttpResponse('第三关没有通过验证')
else:
api_key_record[client_md5_citme] = client_time + 10 # 设置超时时间 10s后超时,然后从列表中删除 if request.method == "GET":
aaa = "重要的数据"
return HttpResponse(aaa)

CMDB API验证的更多相关文章

  1. CMDB 数据加密 最终整合API验证+AES数据加密

    当CMDB运行在内网的时候,经过API验证的三关是没有问题的,但是如果运行在外网,有一个问题是,黑客截取后的访问速度比客户端快的时候还会造成数据泄露.为了解决这个问题,就要对数据进行加密 RSA加密 ...

  2. CMDB服务器管理系统【s5day90】:API验证

    1.认证思路刨析过程 1.请求头去哪里拿? 1.服务器端代码: def test(request): print(request) return HttpResponse('你得到我了') 2.客户端 ...

  3. python API验证

    API验证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 API验证:     a. 发令牌: 静态         PS: 隐患 key ...

  4. API验证及AES加密

    API验证 API验证: a. 发令牌: 静态 PS: 隐患 key被别人获取 b. 动态令牌 PS: (问题越严重)用户生成的每个令牌被黑客获取到,都会破解 c. 高级版本 PS: 黑客网速快,会窃 ...

  5. API验证插件

    前言 如果在访问某WebAPI过程中request信息被他人截获,若是get请求获取数据还好,如果是post提交数据,势必威胁数据安全,所以对于一个对安全性要求较高的API来说,对每个请求做身份验证显 ...

  6. API验证

    API验证说明 API验证: a. 发令牌: 静态 PS: 隐患 key被别人获取 b. 动态令牌 PS: (问题越严重)用户生成的每个令牌被黑客获取到,都会破解 c. 高级版本 PS: 黑客网速快, ...

  7. 基于 JWT-Auth 实现 API 验证

    基于 JWT-Auth 实现 API 验证 如果想要了解其生成Token的算法原理,请自行查阅相关资料 需要提及的几点: 使用session存在的问题: session和cookie是为了解决http ...

  8. CMDB资产管理系统开发【day27】:cmdb API安全认证

    1.API验证分析 API三关验证 客户端和服务端中都存放一份相同的随机字符串,客户端发请求的时候把随机字符串和当前时间进行MD5加密,同时带着当前时间通过请求头发送到API,进入三关验证. 第一关是 ...

  9. Django学习手册 - 基于requests API验证(二)

    原理分析: API接口验证 1.一个认证的key server端 和 client端都必须有这么一个认证key. 2.认证登录的时间限定 3.保存已验证的信息,在以后的验证不能再次登录 client ...

随机推荐

  1. linux命令之ll按时间和大小排序显示

    ll不是命令,是ls -l的别名 按大小排序 [root@localhost ~]# ll -Sh 按时间排序 [root@localhost ~]# ll -rt ll -t 是降序, ll -t ...

  2. jmter介绍及安装

    一.   Apache JMeter介绍 1.       Apache JMeter是什么 Apache JMeter 是Apache组织的开放源代码项目,是一个100%纯Java桌面应用,用于压力 ...

  3. express使用post方法

    express有get.post和在路由后面跟参数,这三种接参方式,这篇文章我主要记录post使用方法 1.json解析中间件(body-parser) cnpm install body-parse ...

  4. NFS服务及DHCPD服务

    NFS 服务 Linux与Linux之间的文件共享 就是网络文件系统,依靠网络. 所有端口都存放在此,对应的服务跟端口 cat /etc/service 部署NFS 先部署服务器端: 部署之前要先启用 ...

  5. mysql5.6数据库同步,单向双向同步问题

    windows下MySQL5.6实现主从数据库同步数据   mysql5.6数据库同步,单向双向同步问题 一.单向同步 主数据库(mysql5.6)192.168.1.104 从数据库(mysql5. ...

  6. CentOS 7 部署 nginx-1.14.2

    参考:http://www.linuxe.cn/post-168.html 链接:https://pan.baidu.com/s/1NzHIY7mYgHJ6yMF_rdd0ZQ 提取码:n8o9 下载 ...

  7. 微信站 - 实现复制功能 clipboard

    <script src="https://cdn.bootcss.com/clipboard.js/1.5.9/clipboard.js"></script> ...

  8. JS高级学习历程-5

    [闭包] 定义:闭包就是一个函数 条件:一个函数去嵌套另外一个函数,里边的函数就是闭包 function  f1(){ function f2(){ } } 特点:闭包函数有权访问父级环境的变量信息.

  9. css3椭圆运动

    通过使用css3实现让元素椭圆运动.而不是圆形运动. 效果1:http://sandbox.runjs.cn/show/ignefell 效果2:http://runjs.cn/code/w2wxjy ...

  10. NET Core应用中实现与第三方IoC/DI框架的整合?

    NET Core应用中实现与第三方IoC/DI框架的整合? 我们知道整个ASP.NET Core建立在以ServiceCollection/ServiceProvider为核心的DI框架上,它甚至提供 ...