在对接很多的互联网公司的开发平台时,这些互联网公司未来自身平台的安全,都会需要调用方签名确认调用方的身份是合法的,同时未来信息网络传输的安全可能还需要加密解密。比如对接支付宝、微信开放平台时,需要配置公钥并下载平台的公钥,后续调用方就需要对请求的报文进行签名,支付宝、微信收到请求后需要验签,只有身份验证通过才能执行相关的业务流程。
在实际的开发过程中,有很多人分不清什么是公钥什么是私钥,如何进行签名验签及加密解密,以及签名验签与加密解密有什么关系。这一期我们就来详细说说这个问题。关于RSA的算法请参考我的文章《安全系列之——RSA的前世今生》,加密解密可以参考我的文章《安全系列之——手写JAVA加密、解密》。
一、公钥私钥
在之前的文章《安全系列之——手写JAVA加密、解密》中,介绍了对称加密和非对称加密。其中非对称加密使用的是RSA算法,所谓的非对称,指的是,加密时使用的秘钥和解密时使用的秘钥是不一样的。也就是说RSA有一对秘钥,其中一个是公钥,另一个是私钥,一个用于加密,一个用于解密。
RAS算法的两个应用是签名验签、加密解密。
在网络通讯过程中,通讯之前,调用方和被调用方都需要生成一对公私钥;然后调用方和被调用方之间交换公钥;这样调用方和被调用方都拥有自己的私钥和对方的公钥,这是双方通讯为了通讯安全就可以做签名验签和加密解密了。
私钥只能自己拥有,不能暴露给任何人,只要私钥不暴露,通讯就是安全的。私钥可以等同于身份。
公钥可以被任何人获取。获取到对方的公钥,就可以通过公钥验证对方的签名;同时使用对方的公钥加密,也只能被对方的私钥解密。
因为公钥是公开的,也为通讯双方的公钥交换提供了便利,不用在考虑交换时是否泄漏了。
二、签名验签与加密解密的关系
首先强调一点,签名验签与加密解密之间没有关系。
签名验签与加密解密都是为了系统安全而做的必要措施,但是是为了防范不同的安全风险。
签名验签
签名验签:是为了验证用户身份是否是合法。比如微信支付,任何合法的商户都可以调用微信支付接口。那么什么是合法商户呢?满足微信的很多要求,比如商户注册微信商户平台获得商户id、签约相关的支付产品获得appid、给开通的支付产品配置商户的公钥并下载微信的公钥,这样的商户对微信来说才是合法的。然后商户使用自己的商户私钥对相关的请求参数进行签名后调用微信的支付接口;微信收到请求后通过商户配置在平台的商户公钥对这个请求进行验签,验签通过说明这个次请求时一个合法的平台商户发起的,验签通过后就可以做具体的支付业务了。
签名为什么用调用方的私钥?签名通常是被调用方(平台)考虑到自身安全要求调用方做签名,从而验证调用方是否合法。考虑的是被调用方的安全。因为合法的商户已经将自己的公钥配置到微信后台了,当一个调用者将加签名的参数传到微信平台,而微信平台恰好能用这个商户配置的公钥验签通过,说明发请求的人就是持有这个私钥的合法商户,因为只有持这个私钥的商户才能做出这个签名,私钥是保密的,不是每个人都有。如果签名使用的是公钥,公钥人人都可以从网上获取,一个非法的调用者也可以获得这个公钥并签名向微信发请求,即使微信平台验签通过也不知道这个调用者是否合法。
加密解密
加密解密:是为了防止数据在网络传输中被人劫持。假如商户调用微信的支付接口时,请求报文中的有很多敏感字段比如银行卡号、密码等(实际不需要这些字段),当报文在网络上传输时,被人恶意监听,就会导致商户的银行卡号和密码泄露,所以商户在调用时就需要使用微信公钥对整个报文进行加密;微信收到请求后,就可以使用微信私钥进行解密,这样就可以防止敏感信息泄露了。当然https已经在传输的时候加密了。
加密为什么用对方的公钥?加密通常是调用方(商户)考虑自身安全,保证调用方的敏感信息不被泄露而做的,保证只有真正的被调用方才能解密。如何保证呢?也就是即使信息在网络传输中被劫持了,也不能解密。要想解密,必须持有秘钥,要想唯一持有秘钥,那就必须是私钥,因为私钥是不对外公开的。能解密,说明这个信息就是发生给他的。所以,信息发给谁,就只能用谁的私钥才能解密,这就必须要求发送方使用他的公钥加密了。信息要发给微信平台,就必须用微信平台的公钥加密。
这里签名验签与加密解密使用的是不同的公私钥。签名时,站在被调用方(微信平台)的角度看,微信要求谁调用微信平台,谁使用自己的私钥做签名;解密时,站在调用方(商户)的角度看,商户把信息发给谁,谁才能使用自己的私钥解密。因为私钥只有自己持有,私钥可以和合法用户划等号。而公钥是全网公开的,谁都能获取。
总结:
签名:A调用B时,B要验证A是否合法(是否能调用接口),A必须使用自己的私钥签名;
解密:A调用B时,A要验证B是否合法(是否能解密),B必须使用自己的私钥解密;
三、测试
这里模拟A给B发消息的过程,测试前,A生成一对公私钥,B生成一对公私钥,然后A和B交互公钥,A拥有 privateKey_A 和publicKey_B,B拥有privateKey_B和publicKey_A。这里只模拟单向(A请求B)的签名验签和加密解密,有兴趣的可以自己模拟双向的(A请求B,以及B响应A)签名验签和加密解密。
关于公私钥的生成可以参考之前的文章《安全系列之——手写JAVA加密、解密》。关注公众号,输入关键字“java-summary”,即可获得源码。
运行结果:
00
关注公众号,输入关键字“java-summary”,即可获得源码。
完成,收工!
【传播知识,共享价值】,感谢小伙伴们的关注和支持,我是【诸葛小猿】,一个彷徨中奋斗的互联网民工!!!