对接第三方服务引起的小思考-回调和Sign算法
背景
最近在对接一个同事写的支付公用模块,然后对第三方服务引起一两个小思考。
思考
回调
来看看我们同事是如何做回调的。
首先,请求支付接口的时候,将回调URL作为请求body的一个参数[不加密]。
{
"xxx": "xxx",
"xxx": "xx",
"xxxxx": "xxxxx",
"callBackUrl": "http://www.baidu.com"
}
然后,当第三方支付服务成功后,支付服务会对上面的回调URL发出一次http请求,然后固定请求体带上以下参数:
{
"code": 0,
"充值订单号": "3333333333333333",
"支付订单号": 361504175005106176,
"支付状态": "SUCCESS",
"充值数额": 88.00,
"subject": "游戏",
"gmtCreate": "2019-08-21 10:49:21",
"gmtPayment": "2019-08-21 10:49:21",
}
到这里,我们可以看到
1、回调url是没有加密的,那么如果有黑客拦截到此数据,就可以拿到此url不断地攻击服务器了。
2、回调时的参数是支付服务方固定的,而且没有做到扩展,调用方不能增加自定义参数。
那么比较好的解决方案有什么呢,我们可以参考一下阿里的对象存储OSS是怎么做的。
Callback
用户只需要在发送给 OSS 的请求中携带相应的 Callback 参数,即能实现回调。
Callback包含下面字段(json格式):
{
"callbackUrl":"121.101.166.30/test.php", // 回调url
"callbackHost":"oss-cn-hangzhou.aliyuncs.com", // 回调host
"callbackBody":"{\"mimeType\":${mimeType},\"size\":${size}}", //回调请求体
"callbackBodyType":"application/json" // 回调请求体类型
}
然后将Callback对象转成Json字符串,再进行Base64编码,最后将Base64编码后的字符串作为一个请求参数即可。最后的请求体可能为如下:
{
"xxx": "xxx",
"xxx": "xx",
"xxxxx": "xxxxx",
"callBack": "23jdf7adf8gfasg98g78a9dgda"
}
这样的话,我们可以看到,这就算是被别人拦截了,第一眼看过去肯定是懵逼的。但是呢,只要猜到是base64编码的,反编码后还是可以看到里面的东西。如果对安全性的要求是极致的,大家还可以加上加密算法[可解密],千万不要加密完不能倒退回来。。。
Sign算法
一般的Sign算法,将请求参数以key1=value2&key2=value2的格式拼接起来,然后再拼接header的参数,最后的格式为:hKey1=hValue2&hKey2=hValue2&data=xxxx,而data的值就是上面请求参数拼接后的字符串,最后进行加密。
我们可以想象,如果客户端的拼接顺序和服务端拼接的顺序不一致,那么最后加密后的字符串肯定是不相等,那么最后必须是服务端返回一句话:签名不合法。
下面,我们看一下一开始SignUtil中对请求参数的拼接函数:
/**
* 将参数进行拼接
* 返回结果为: key1=value1&key2=value2&key3=value3
*
* @param map Map参数
* @return String
*/
public static String mapToString(Map<String, Object> map) {
StringBuffer builder = new StringBuffer();
map.forEach((key, value) -> builder.append(key).append("=").append(value).append("&"));
builder.deleteCharAt(builder.length() - 1);
return builder.toString();
}
我们可以看到,是遍历Map来进行拼接。Map如果以顺序分类,可以分为两大类:一种是有序(例如LinkedHashMap和TreeMap),一种是无序(HashMap)。如果支付服务提供的SignUtil提供的拼接方法如上,那么就是说,我们开发者并不知道支付服务端是传入哪种类型的Map来进行拼接;这时候如果支付服务端使用的是TreeMap,而我们自己在不知道的前提下使用了比较常用的HashMap,那么这时候就出大问题了,签名永远是错误的。
解决方法(支付服务方提供SignUtil):
1、第三方服务的开发文档必须提醒开发者该传入的Map类型。
拼接方法传入参数还是可以为Map,因为利用了泛型这样比较通用,但是呢文档该注重提醒开发者是传入有序的还是无序的实现类。
2、拼接方法传入参数指定Map类型,甚至具体到实现类。
虽然说这样没有使用到泛型,显得不够通用,可是正因为如此,能强制规定开发者的输入,能避免非常多不必要的坑。
/**
* 将参数进行拼接
* 返回结果为: key1=value1&key2=value2&key3=value3
*
* @param map HashMap参数
* @return String
*/
public static String mapToString(HashMap<String, Object> map) {
StringBuffer builder = new StringBuffer();
map.forEach((key, value) -> builder.append(key).append("=").append(value).append("&"));
builder.deleteCharAt(builder.length() - 1);
return builder.toString();
}
总结
如果是做提供第三方服务的程序猿,我们必须考虑到接口的通用性,还有更重要的是准确性;然后还有就是文档应该简洁而不简单,能让开发者看文档即可一次搞定对接,而不是浪费不必要的时间去尝试,去揣测第三方服务究竟是如何设计的。
对接第三方服务引起的小思考-回调和Sign算法的更多相关文章
- 如何更优雅地对接第三方API
本文所有示例完整代码地址:https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/third 我们在日常开发过程 ...
- Java 后端开发常用的 10 种第三方服务
请肆无忌惮地点赞吧,微信搜索[沉默王二]关注这个在九朝古都洛阳苟且偷生的程序员.本文 GitHub github.com/itwanger 已收录,里面还有我精心为你准备的一线大厂面试题. 严格意义上 ...
- 微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Nginx 为基础的 API 网关详细介绍
微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Nginx 为基础的 API 网关详细介绍 一.为什么会有 API Gateway 网关 随着微服务架构的流行,很多公司把原有的单 ...
- 对接第三方支付接口-获取http中的返回参数
这几天对接第三方支付接口,在回调通知里获取返回参数,有一家返回的json格式,请求参数可以从标准输入流中获取. //1.解析参数 , 读取请求内容 BufferedReader br; String ...
- 数据中心第三方服务、金融IT外包服务、社保医疗信息化解决方案,这三类业务是什么关系,区别在哪?
这个话题很大,牵扯很多,试着回答一下,算是胡扯了. 三类业务的关系,都是IT外包,至于外包的内容很杂.DC的外包,多半是基建和建维,一般不牵扯到软件开发,网站建设类的.金融IT外包就复杂多了,信息系统 ...
- 《深入理解Nginx》阅读与实践(三):使用upstream和subrequest访问第三方服务
本文是对陶辉<深入理解Nginx>第5章内容的梳理以及实现,代码和注释基本出自此书. 一.upstream:以向nginx服务器的请求转化为向google服务器的搜索请求为例 (一)模块框 ...
- 如何从零开始对接第三方登录(Java版):QQ登录和微博登录
前言 个人网站最近增加了评论功能,为了方便用户不用注册就可以评论,对接了QQ和微博这2大常用软件的一键登录,总的来说其实都挺简单的,可能会有一点小坑,但不算多,完整记录下来方便后来人快速对接. 后台设 ...
- Heroku第三方服务接入指南(二)
上文我们讲了第三方服务.Heroku.用户三者的关系,这一篇进入正题,了解第三方厂商(下文简称厂商)怎样为Heroku开发服务.这里仅仅做简介,了解heroku大致是怎么做的.假设你的平台.希望接入第 ...
- kubernetes对接第三方认证
kubernetes对接第三方认证 kubernetes离线安装包地址 概述 本文介绍如何使用github账户去关联自己kubernetes账户.达到如下效果: 使用github用户email作为ku ...
随机推荐
- 图论之拓扑排序 poj 2367 Genealogical tree
题目链接 http://poj.org/problem?id=2367 题意就是给定一系列关系,按这些关系拓扑排序. #include<cstdio> #include<cstrin ...
- 牛客多校第五场 E room 二分图匹配 KM算法模板
链接:https://www.nowcoder.com/acm/contest/143/E来源:牛客网 Nowcoder University has 4n students and n dormit ...
- JS-DOM ~ 02. 隐藏二维码、锁定、获取输入框焦点、for循环为文本赋值、筛选条件、全选和反选、属性的方法操作、节点的层次结构、nodeType
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 【Hystrix】实现服务隔离和降级
一.背景 1.1 服务熔断 1.2 服务降级 1.3 服务隔离 1.4 总结 二.使用Hystrix实现服务隔离和降级 2.1 Hytrix 简介 2.2 线程池方式 2.3 信号量 三.项目搭建 3 ...
- Python 的整数与 Numpy 的数据溢出
某位 A 同学发了我一张截图,问为何结果中出现了负数? 看了图,我第一感觉就是数据溢出了.数据超出能表示的最大值,就会出现奇奇怪怪的结果. 然后,他继续发了张图,内容是 print(100000*20 ...
- vue.js安装教程
vue.js环境搭建 1.下载node.js 网址:https://nodejs.org/en/ 版本:v10.16.3 2.安装node.js Node.js下载如下所示: 检查nodejs是否安装 ...
- 深入Go的错误处理机制使用
开篇词 程序运行过程中不可避免的发生各种错误,要想让自己的程序保持较高的健壮性,那么异常,错误处理是需要考虑周全的,每个编程语言提供了一套自己的异常错误处理机制,在Go中,你知道了吗?接下来我们一起看 ...
- 【LeetCode】DFS 总结
DFS(深度优先搜索) 常用来解决可达性的问题. 两个要点: 栈:用栈来保存当前节点信息,当遍历新节点返回时能够继续遍历当前节点.可以使用递归栈. 标记:和 BFS 一样同样需要对已经遍历过的节点进行 ...
- ie表单提交提示下载文件
使用jquery的ajaxform提交form表单 如果在html中多了 enctype ="multipart/form-data" 属性值 提交时就会在ie8中提示下载 ...
- Tomcat9控制台中文乱码的解决方案
1.网上大部分都是这种方法 注释掉 tomcat 9 安装目录下的conf里的 logging.properties 找到 java.util.logging.ConsoleHandler.encod ...