第五节、项目支付功能实战-证书获取、微信支付集成初始化配置、sdk统一下单、api安全源码解读_微信支付获取平台证书

  List<X509Certificate> certs = new ArrayList<>();
  certs.add(certificate);

  CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
  CertPath certPath = cf.generateCertPath(certs);

  CertPathValidator validator = CertPathValidator.getInstance("PKIX");
  validator.validate(certPath, params);

上述代码块用于检查证书是否由可信的根证书颁发,以及证书是否有效。X509Certificate是一种常用的数字证书标准。首先创建一个 PKIXParameters 类型的对象,它是一个用于验证证书路径的参数集合,它的构造器需要一个 trustAnchor 参数,表示可信的根证书,它是一个 Set 类型的对象,它包含了一个或多个根证书的信息。 getInstance(“PKIX”) 返回一个支持 PKIX(公钥基础设施)算法的验证器实例。


证书下载完成会存放到 AutoCertificateService类certificateMap中 ,certificateMap 是一个ConcurrentHashMap ,是线程安全的,可以支持多线程的并发访问和修改,而AutoCertificateService类是一个定时更新证书的服务,它是一个由静态函数构成的工具类。



private static final ConcurrentHashMap<String, Map<String, X509Certificate>> certificateMap =
new ConcurrentHashMap<>();
Map<String, X509Certificate> result = downloader.download();
certificateMap.put(key, result);


**到此微信平台证书的自动下载过程就描述清楚了,下面我们来总结一下具体流程:**


(1)商户侧包装商户信息:商户号、商户公钥、商户私钥等信息,并将请求的数据进行签名。将签名和公钥、时间戳、随机数等信息打包成token放到请求头部发送至微信平台侧。  
 (2)微信测收到请求后获取到认证token,并解析出商户公钥和明文信息,对数据进行验签。同时使用APIv3密钥将证书进行加密同步返回给商户侧。  
 (3)商户侧收到微信侧的响应数据后,从响应数据解密出证书,应答报文解密后,生成X.509证书对象,也就是将证书从String转为X509Certificate。  
 (4)验证证书的有效性  
 (5)将证书存储到AutoCertificateService中的certificateMap 中。


### APIv3密钥设置


在商户平台中【微信支付商户平台 - 账户中心 - 账户设置 - API安全 - APIv3密钥设置】,这个可使用在线生成器生成地址:<https://www.bchrt.com/tools/suijimima/>


### 商户平台证书和私钥的获取


以下内容来自微信官网:<https://kf.qq.com/faq/161222NneAJf161222U7fARv.html>  
 1、登录【微信支付商户平台 - 账户中心 - 账户设置 - API安全 - 申请API证书】申请证书,确定后请勿关闭页面  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/cbaca4d8c8d4484f8c5b7d5c8d16efeb.png)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/6a95dfab21a74656ae97b87191350bcd.png)  
 2、点击下载证书工具;下载后,双击“WXCertUtil.exe”文件,选择安装路径后,点击申请证书


也可通过以下链接下载证书工具:


[windows版本]( )   
 [mac版本]( ) 


3、在【证书工具】,填写商户号信息(商户号、商户名称),点击下一步  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b09a7289e9e94f8d9cf0ca5f8dc4f539.png)  
 4、在【证书工具】,复制证书请求串  
 (若提示"请粘贴请求串到商户平台获取证书串",请在第5点步骤检查是否已粘贴。可同时尝试手动鼠标复制粘贴的方法)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b409a322a77c4a82aa43ff5ee92b8778.png)  
 5、在【商户平台】,粘贴证书请求串  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/5de170cb9112467f902a62a73db1bed6.png)  
 6、在【商户平台】,输入操作密码,安全验证后生成证书串  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/fee6d72cd64d4db98605725c84fac0f4.png)  
 7、在【商户平台】,复制证书串  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/cf5fdb9f8925455ba8dab48ac2239327.png)  
 8、在【证书工具】,粘贴证书串,点击下一步,申请证书成功  
 (若提示"证书与本地公私钥不匹配",可能是浏览器禁用了剪切板复制功能。请在操作步骤第7点,操作时使用鼠标选中全部证书串内容(注意右边有下拉框),单击鼠标右键选择复制)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/0d59a1586680427e8517d9471164ba4c.png)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ca2c1ee7c0284b339f1dfe959b70aa69.png)  
 提醒:请将生成的证书文件转交给技术人员,由技术人员将证书部署到服务器上(请务必妥善保管证书及私钥,因为私钥文件只能通过证书工具导出,若私钥丢失,则无法找回,只能作废后重新申请。)


9、证书申请成功后,在证书文件夹中解压文件会发现有3个文件:.p12 这个不用管,其中两个文件apiclient\_cert.pem(商户公钥文件)、apiclient\_key(商户私钥文件)。


到此,商户API证书已经获取完毕。


### 初始化微信配置


为了统一配置微信支付用到的信息,我们在项目的resource目录下创建一个配置文件`wxpay.properties`



商户号

wxpay.mch-id=xxxxxxx

微信商户证书序列号

wxpay.mch-serial-no=xxxxxxxxxxxxxxxxxxx

商户私钥(路径加载方式使用)

wxpay.private-key-path=apiclient_key.pem

APIv3密钥

wxpay.api-v3-key=xxxxxxxxxxxxxx

小程序APPID

wxpay.appid=xxxxxxxxxxx

微信小程序密钥

wxpay.appSecret=xxxxxxxxxxxxxxxxxxxxxxxxx

微信商户平台域名(调用接口时的通用域名)

wxpay.domain=https://api.mch.weixin.qq.com
#微信支付回调地址域名(需要https 并且为备案的域名)
wxpay.notify-domain=https://test.notify.com
#商户私钥
wxpay.private-key=-----BEGIN PRIVATE KEY-----xxxx-----END PRIVATE KEY-----


其对应的配置类如下:



@Configuration
@PropertySource(“classpath:wxpay.properties”) //读取配置文件
@ConfigurationProperties(prefix=“wxpay”) //读取wxpay节点
@Data //使用set方法将wxpay节点中的值填充到当前类的属性中
public class WxPayConfig {

// 商户号
private  String mchId;

// 商户API证书序列号
private  String mchSerialNo;  

// 商户私钥文件
private  String privateKeyPath;

// APIv3密钥
private  String apiV3Key;

// APPID
private String appid;
//小程序密钥
private String appSecret;
// 微信服务器地址
private String domain;

// 接收结果通知地址
private String notifyDomain;

// APIv2密钥
private String partnerKey;

//商户私钥字符串
private String privateKey;

}


### 小程序统一下单


本节,主要来以分析小程序统一下单的案例,来说明sdk的使用方式,以及商户证书和平台证书的在调用下单接口时是如何使用的,本节不会过多在当前项目中展开业务代码,只讲解下单接口如何调用,安全验证的过程。


在调用小程序下单接口之前,首先要创建订单数据,调用下单接口时将订单数据传过去,比如订单金额、商品id、订单编号等。微信收到订单后会返回预付订单id以及微信平台返回的微信订单信息,下面来看看具体的调用代码,下面是小程序下单的代码块。



if (config == null){
config = WxInitUtils.getInstance(wxPayConfig);
}
JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
// 填充预下单参数
PrepayRequest request = new PrepayRequest();
//appid
request.setAppid(wxPayConfig.getAppid());
//商户id
request.setMchid(wxPayConfig.getMchId());
//产品描述
assert orderInfo != null;
request.setDescription(orderInfo.getOrderTitle());
//商户订单号
request.setOutTradeNo(orderInfo.getOrderNo());
//通知url
request.setNotifyUrl(wxPayConfig.getNotifyDomain().concat(WxNotifyType.NATIVE_NOTIFY.getType()));

    //金额信息
    Amount amount = new Amount();
    amount.setTotal(orderInfo.getTotalFee());
    amount.setCurrency("CNY");
    request.setAmount(amount);

    //用户信息
    Payer payer = new Payer();
    payer.setOpenid(openId.toString());
    request.setPayer(payer);

    log.info("请求参数 ===> {}" + request.toString());
    PrepayWithRequestPaymentResponse response = null;

    try {
        // response包含了调起支付所需的所有参数,可直接用于前端调起支付
        response = service.prepayWithRequestPayment(request);
    } catch (Exception e) {
        log.error("请求下单失败,错误信息" + e.getMessage());
        throw new RuntimeException("请求下单失败,错误信息" + e.getMessage());
    }

    //处理返回值
    assert response != null;
    String packageVal = response.getPackageVal();
    String prepayId = packageVal;

上述代码中,首先拿到配置信息config,然后调用`JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();` 这个是sdk提供的api,接下来组装好参数之间向微信发起请求,请求的代码段`response = service.prepayWithRequestPayment(request);` 在prepayWithRequestPayment方法中调用了String prepayId = this.jsapiService.prepay(request).getPrepayId(); 在prepay方法中才是真正的发起请求,重点来看下请求的代码段:



HttpRequest httpRequest = (new HttpRequest.Builder()).httpMethod(HttpMethod.POST).url(requestPath).headers(headers).body(this.createRequestBody(request)).build();
HttpResponse httpResponse = this.httpClient.execute(httpRequest, PrepayResponse.class);


在execute方法中又调用了如下代码,和下载证书的接口调用是一样的。



HttpRequest innerRequest =
new Builder()
.url(httpRequest.getUrl())
.httpMethod(httpRequest.getHttpMethod())
.headers(httpRequest.getHeaders())
.addHeader(AUTHORIZATION, getAuthorization(httpRequest))
.addHeader(USER_AGENT, getUserAgent())
.body(httpRequest.getBody())
.build();
OriginalResponse originalResponse = innerExecute(innerRequest);
validateResponse(originalResponse);


重点来关注Authorization, 的组成如下:



> 
> Authorization: 认证类型 签名信息
> 
> 
> 


具体组成为:  
 **认证类型:** 目前为WECHATPAY2-SHA256-RSA2048  
 **签名信息**  
 发起请求的商户(包括直连商户、服务商或渠道商)的商户号mchid  
 商户API证书序列号serial\_no,用于声明所使用的证书  
 请求随机串nonce\_str  
 时间戳timestamp  
 签名值signature


示例如下:



> 
> ‘Authorization: WECHATPAY2-SHA256-RSA2048 mchid=“1900009191”,nonce\_str=“593BEC0C930BF1AFEB40B4A08C8FB242”,signature=“uOVRnA4qG/MNnYzdQxJanN+zU+lTgIcnU9BxGw5dKjK+VdEUz2FeIoC+D5sB/LN+nGzX3hfZg6r5wT1pl2ZobmIc6p0ldN7J6yDgUzbX8Uk3sD4a4eZVPTBvqNDoUqcYMlZ9uuDdCvNv4TM3c1WzsXUrExwVkI1XO5jCNbgDJ25nkT/c1gIFvqoogl7MdSFGc4W4xZsqCItnqbypR3RuGIlR9h9vlRsy7zJR9PBI83X8alLDIfR1ukt1P7tMnmogZ0cuDY8cZsd8ZlCgLadmvej58SLsIkVxFJ8XyUgx9FmutKSYTmYtWBZ0+tNvfGmbXU7cob8H/4nLBiCwIUFluw==”,timestamp=“1554208460”,serial\_no=“1DDE55AD98ED71D6EDD4A4A16996DE7B47773A8C”’
> 
> 
> 


以上就是签名的过程,使用商户私钥签名,签名后之间发送到了微信平台,所以小程序统一下单,并没有加密的操作,只有签名的操作。同样微信同步响应后,也需要在商户侧进行验签。


sdk中验签的代码段如下:



String timestamp = responseHeaders.getHeader(WECHAT_PAY_TIMESTAMP);
try {
Instant responseTime = Instant.ofEpochSecond(Long.parseLong(timestamp));
// 拒绝过期请求
if (Duration.between(responseTime, Instant.now()).abs().toMinutes()
>= RESPONSE_EXPIRED_MINUTES) {
throw new IllegalArgumentException(
String.format(
"Validate http response,timestamp[%s] of httpResponse is expires, "
+ “request-id[%s]”,
timestamp, responseHeaders.getHeader(REQUEST_ID)));
}
} catch (DateTimeException | NumberFormatException e) {
throw new IllegalArgumentException(
String.format(
“Validate http response,timestamp[%s] of httpResponse is invalid, request-id[%s]”,
timestamp, responseHeaders.getHeader(REQUEST_ID)));
}
String message =
timestamp
+ “\n”
+ responseHeaders.getHeader(WECHAT_PAY_NONCE)
+ “\n”
+ (responseBody == null ? “” : responseBody)
+ “\n”;
logger.debug(“Message for verifying signatures is[{}]”, message);
String serialNumber = responseHeaders.getHeader(WECHAT_PAY_SERIAL);
logger.debug(“SerialNumber for verifying signatures is[{}]”, serialNumber);
String signature = responseHeaders.getHeader(WECHAT_PAY_SIGNATURE);
logger.debug(“Signature for verifying signatures is[{}]”, signature);
return verifier.verify(serialNumber, message, signature);


验证签名要经过以下几个步骤:  
 **(1)校验微信响应的时间戳是否过期,有效时间为5分钟,// 拒绝过期请求**  
 if (Duration.between(responseTime, Instant.now()).abs().toMinutes()  
 >= RESPONSE\_EXPIRED\_MINUTES) 目的是防止重放攻击,[重放攻击]( ) 是指攻击者截取报文及其签名,并以恶意或欺诈目的重新传输数据的一种攻击手段。 为了降低此类攻击的风险,微信支付在 HTTP 头 Wechatpay-Timestamp 中提供了生成签名的时间戳。若微信支付需要重新发送某个通知回调,我们也会重新生成相应的时间戳和签名。在验证签名之前,商户系统应检查时间戳是否已过期。我们建议商户系统允许最多5分钟的时间偏差。如果时间戳与当前时间的偏差超过5分钟,您应拒绝处理当前的响应或回调通知。


**(2)构造验签名串**  
 构造验签名串由3个部分组成 ,应答或通知回调中获取以下信息:  
 HTTP 头 Wechatpay-Timestamp 中的应答时间戳  
 HTTP 头 Wechatpay-Nonce 中的应答随机串  
 应答报文主体(Response Body),请使用原始报文主体执行验签。如果您使用了某个框架,要确保它不会篡改报文主体。对报文主体的任何篡改都会导致验证失败。


**(3)验证微信平台证书是否正确**  
 检查 HTTP 头 Wechatpay-Serial 的内容是否跟商户当前所持有的微信支付平台证书的序列号一致。若不一致,请重新获取证书。否则,签名的私钥和证书不匹配,将验证失败。重点代码如下:根据头部返回的证书序列号查询下载时存放的证书是否一致。



/**
* 根据证书序列号获取证书
*
* @param serialNumber 微信支付平台证书序列号
* @return X.509证书实例
*/
@Override
public X509Certificate getCertificate(String serialNumber) {

如何自学黑客&网络安全

黑客零基础入门学习路线&规划

初级黑客
1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)

2、渗透测试基础(一周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等

3、操作系统基础(一周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)

4、计算机网络基础(一周)
①计算机网络基础、协议和架构
②网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
④网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现

5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固

6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)
恭喜你,如果学到这里,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web 渗透、安全服务、安全分析等岗位;如果等保模块学的好,还可以从事等保工程师。薪资区间6k-15k

到此为止,大概1个月的时间。你已经成为了一名“脚本小子”。那么你还想往下探索吗?

如果你想要入坑黑客&网络安全,笔者给大家准备了一份:282G全网最全的网络安全资料包评论区留言即可领取!

7、脚本编程(初级/中级/高级)
在网络安全领域。是否具备编程能力是“脚本小子”和真正黑客的本质区别。在实际的渗透测试过程中,面对复杂多变的网络环境,当常用工具不能满足实际需求的时候,往往需要对现有工具进行扩展,或者编写符合我们要求的工具、自动化脚本,这个时候就需要具备一定的编程能力。在分秒必争的CTF竞赛中,想要高效地使用自制的脚本工具来实现各种目的,更是需要拥有编程能力.

如果你零基础入门,笔者建议选择脚本语言Python/PHP/Go/Java中的一种,对常用库进行编程学习;搭建开发环境和选择IDE,PHP环境推荐Wamp和XAMPP, IDE强烈推荐Sublime;·Python编程学习,学习内容包含:语法、正则、文件、 网络、多线程等常用库,推荐《Python核心编程》,不要看完;·用Python编写漏洞的exp,然后写一个简单的网络爬虫;·PHP基本语法学习并书写一个简单的博客系统;熟悉MVC架构,并试着学习一个PHP框架或者Python框架 (可选);·了解Bootstrap的布局或者CSS。

8、超级黑客
这部分内容对零基础的同学来说还比较遥远,就不展开细说了,附上学习路线。
img

网络安全工程师企业级学习路线

img
如图片过大被平台压缩导致看不清的话,评论区点赞和评论区留言获取吧。我都会回复的

视频配套资料&国内外网安书籍、文档&工具

当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。

img
一些笔者自己买的、其他平台白嫖不到的视频教程。
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以点击这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 11
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值