💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[toc] # 接口常见的安全问题 * 数据篡改 * DOS攻击/高频请求 # 接口安全的解决策略 * 全参加密 * 一次性接口(记录+超时) # 代码思路 ```[sequence] title:接口请求时序图 participant APP as app participant 服务器 as server participant 服务器缓存 as cache app->server: APP带参数访问服务器 note left of app: 检查请求是否包含安全参数 server->server:参数中是否包含安全参数time server-->app: 返回错误: 缺少安全参数 time! server->server:参数中是否包含安全参数token server-->app: 返回错误: 缺少安全参数 token! note left of app: 确保接口请求的一次性 server->cache: 以token为键名查询缓存的请求记录 cache-->server: 返回请求记录查询结果 server-->app: 返回错误: 该接口已经请求过一次! note left of app: 确保接口请求没有超时 server->server: 请求时间戳和服务器时间戳比对 server-->app: 返回错误: 请求超时! note left of app: 确保接口数据没有篡改 server->server: 参数时间戳加密生成随机字符串 server->server: 参数去除token后排序并加密, 生成token server->server: 把参数中的token和服务器生成的token进行比对 server-->app: token不正确! note left of app: 缓存接口请求记录 server->cache: 把此次请求写入缓存 server->cache: 清除缓存中超时的记录 note left of app: 通过验证 server->server: 进行下面的逻辑运算... ``` # 代码示例(python2) ```python # 建立token缓存, 实现接口一次性处理 token_cache_dict = dict() # 构造返回数据 private_key = 'public_bike_project' response_data = dict() response_data['data'] = dict() # 获取post过来的参数 post_dicts = self.request.body_arguments post_dict = dict() for k, v in post_dicts.items(): post_dict[k] = v[0] # 判断是否有time和token这两个关键参数 if not post_dict.has_key('time'): response_data['ret'] = 2 response_data['data']['msg'] = '缺少安全参数 time!' self.write(json.dumps(response_data)) return False if not post_dict.has_key('token'): response_data['ret'] = 2 response_data['data']['msg'] = '缺少安全参数 token!' self.write(json.dumps(response_data)) return False # 如果有, 把这两个关键参数存起来 app_time = post_dict['time'] app_token = post_dict['token'] # 接口一次性认证(缓存中是否有相同token) if self.token_cache_dict.has_key(app_token): response_data['ret'] = 2 response_data['data']['msg'] = '该接口已经请求过一次!' self.write(json.dumps(response_data)) return False # 获取服务器毫秒级时间戳, 用于比对接口请求是否超时 server_time = int(round(time.time() * 1000)) # 判断请求是否超时(300秒) if (server_time - int(app_time)) > 300000: response_data['ret'] = 1 response_data['data']['msg'] = '请求超时!' self.write(json.dumps(response_data)) return False # 生成随机字符串, 生成token时要用 noncestr = self.make_sign(self.make_sign(app_time) + private_key) # 取出token app_token = post_dict['token'] post_dict.pop('token') # 所有参数排序后加key, md5 pre_str = self.sort_data(post_dict) str_for_token = pre_str + "&key=" + noncestr server_token = self.make_sign(str_for_token) # 根据参数生成token, 比对token if app_token != server_token: response_data['ret'] = 2 response_data['data']['msg'] = 'token不正确!' self.write(json.dumps(response_data)) return False # 最终验证通过, 把token缓存中超时的token去掉, 并把本次token加入token缓存 server_time = int(round(time.time() * 1000)) for k, v in self.token_cache_dict.items(): if (server_time - v) > 300000: del self.token_cache_dict['k'] # 请求没有问题, 把此次请求记录写入缓存 self.token_cache_dict[app_token] = server_time return True ``` # 扩展阅读 * [API接口安全性设计](https://www.jianshu.com/p/c6518a8f4040)