前言
如果在访问某WebAPI过程中request信息被他人截获,若是get请求获取数据还好,如果是post提交数据,势必威胁数据安全,所以对于一个对安全性要求较高的API来说,对每个请求做身份验证显得尤为重要;
防范策略解析
策略1
客户端发送http请求访问API时,在请求头里设置一个双方约定好的key;
知识点:
1、如果给Django程序发送请求头,headers携带内容包含下滑杠 _,Django会不认识;
2、客户端 auth-api ----->服务端 转换成 'HTTP_AUTH_API'格式
3、服务端获取clent_key=request.META.get('HTTP_AUTH_API')
客户端
import requests key='sssdkjrjefjewfakfhkj' respose=requests.get(url='http://127.0.0.1:8000/test.html/',headers={'auth-api':key}).text #如果给Django程序发送请求头,如果headers里面的内容使用下滑杠 _,Django会不认识; #auth-api -----> 转换成 'HTTP_AUTH_API'格式 #服务端获取clent_key=request.META.get('HTTP_AUTH_API') print(respose)
服务端
def test(request): key='sssdkjrjefjewfakfhkj' clent_key=request.META.get('HTTP_AUTH_API') if clent_key == key: return HttpResponse('你得到我了') else: return HttpResponse('休想')
漏洞:虽然双方约定好了key,但是请求头依然会被截获到;
策略2
1.key+当前客户端时间戳 组成1个MD5加密字符串
2.MD5加密字符串|当前时间戳 组成1串密码,hearder携带
3.服务端接收到客户端发送的那1串密码,split 出客户端时间
4.来着客户端时间+服务端key做MD5加密还原,对比客户端和服务端
客户端
import requests import time import hashlib key='sssdkjrjefjewfakfhkj' ctime=str(time.time()) def MD5(arg): hs=hashlib.md5() hs.update(arg.encode('utf-8')) #python3加密使用字节类型 return hs.hexdigest() new_key='%s|%s' % (key,ctime) # sssdkjrjefjewfakfhkj | 时间戳 md5_str=MD5(new_key) auth_api_val='%s|%s'%(md5_str,ctime) #d0e0ca7d1f8f72d60715696d4baac3b2(key和时间戳加密后的结果)| 时间戳 print(md5_str) respose=requests.get(url='http://127.0.0.1:8000/test.html/',headers={'auth-api':auth_api_val}).text print(respose)
服务端
import hashlib import time def MD5(arg): hs = hashlib.md5() hs.update(arg.encode('utf-8')) # python3加密使用字节类型 return hs.hexdigest() def test(request): key='sssdkjrjefjewfakfhkj' auth_api_val=request.META.get('HTTP_AUTH_API') #052dd27c130f4b9b5a8a4ec4b243962d | 1507374976.4620001 client_md5_str,client_ctime =auth_api_val.split('|',maxsplit=1) server_md5_str=MD5('%s|%s'%(key,client_ctime)) if client_md5_str== server_md5_str: return HttpResponse('你得到我了') else: return HttpResponse('休想')
漏洞:折腾了半天虽然可以动态加密,但依然可以获取到,且客户端会生成很多加密字符串,黑客获取任意一个都可以访问到API
策略3
1.key+当前客户端时间戳 组成1个MD5加密字符串
2.MD5加密字符串|当前时间戳 组成1串密码,hearder携带
3.服务端接收到客户端发送的那1串密码,split 出客户端时间
4.来着客户端时间+服务端key做MD5加密还原,对比客户端和服务端是否相等
5.动态密码有时间限制,超过5秒失效
客户端
import requests import time import hashlib key='sssdkjrjefjewfakfhkj' ctime=str(time.time()) def MD5(arg): hs=hashlib.md5() hs.update(arg.encode('utf-8')) #python3加密使用字节类型 return hs.hexdigest() new_key='%s|%s' % (key,ctime) # sssdkjrjefjewfakfhkj | 时间戳 md5_str=MD5(new_key) auth_api_val='%s|%s'%(md5_str,ctime) #d0e0ca7d1f8f72d60715696d4baac3b2(key和时间戳加密后的结果)| 时间戳 print(md5_str) respose=requests.get(url='http://127.0.0.1:8000/test.html/',headers={'auth-api':auth_api_val}).text print(respose)
服务端
def test(request): server_float_ctime=time.time() key='sssdkjrjefjewfakfhkj' auth_api_val=request.META.get('HTTP_AUTH_API') #052dd27c130f4b9b5a8a4ec4b243962d | 1507374976.4620001 client_md5_str,client_ctime =auth_api_val.split('|',maxsplit=1) client_float_ctime=float(client_ctime) if client_float_ctime+5 < server_float_ctime: return HttpResponse('想要破解密码最在5秒之内') server_md5_str = MD5('%s|%s' % (key, client_ctime)) if client_md5_str== server_md5_str: return HttpResponse('你得到我了') else: return HttpResponse('休想')
漏洞:虽然加密字符串有了时间限制,但时间就是漏洞
策略4
1.key+当前客户端时间戳 组成1个MD5加密字符串
2.MD5加密字符串|当前时间戳 组成1串密码,hearder携带
3.服务端接收到客户端发送的那1串密码,split 出客户端时间
4.来着客户端时间+服务端key做MD5加密还原,对比客户端和服务端是否相等
5.动态+加密字符串+时间限制,超过5秒失效
6.记录最近5秒访问客户端的加密字符串,如果当前客户端使用的字符串存在记录中,说明是窃取(因为正常用户每次,访问API会携带不同的加密字符串)
客户端
import requests import time import hashlib key='sssdkjrjefjewfakfhkj' ctime=str(time.time()) def MD5(arg): hs=hashlib.md5() hs.update(arg.encode('utf-8')) #python3加密使用字节类型 return hs.hexdigest() new_key='%s|%s' % (key,ctime) # sssdkjrjefjewfakfhkj | 时间戳 md5_str=MD5(new_key) auth_api_val='%s|%s'%(md5_str,ctime) #d0e0ca7d1f8f72d60715696d4baac3b2(key和时间戳加密后的结果)| 时间戳 print(md5_str) respose=requests.get(url='http://127.0.0.1:8000/test.html/',headers={'auth-api':auth_api_val}).text print(respose) #如果给Django程序发送请求头,如果headers里面的内容使用下滑杠 _,Django会不认识; #auth-api -----> 转换成 'HTTP_AUTH_API'格式 #服务端获取clent_key=request.META.get('HTTP_AUTH_API')
服务端
import hashlib import time def MD5(arg): hs = hashlib.md5() hs.update(arg.encode('utf-8')) # python3加密使用字节类型 return hs.hexdigest() visited_keys={} #使用memcached redis 超时时间5秒 def test(request): server_float_ctime=time.time() key='sssdkjrjefjewfakfhkj' auth_api_val=request.META.get('HTTP_AUTH_API') #052dd27c130f4b9b5a8a4ec4b243962d | 1507374976.4620001 client_md5_str,client_ctime =auth_api_val.split('|',maxsplit=1) client_float_ctime=float(client_ctime) #第1关时间限制 if client_float_ctime+5 < server_float_ctime: return HttpResponse('想要破解密码最在5秒之内') #第二关 MD5加密 server_md5_str = MD5('%s|%s' % (key, client_ctime)) if client_md5_str != server_md5_str: return HttpResponse('休想') #第三关 if visited_keys.get(client_md5_str): return HttpResponse('你放弃吧') visited_keys[client_md5_str]=client_float_ctime return HttpResponse('OK')
漏洞:待各位看官补充。。。。