好的网站建站公司,可以做策略回测的网站,湖南城市建设技术学院官方网站,济源网站建设价格简介
HTTP接口是互联网各系统之间对接的重要方式之一#xff0c;使用HTTP接口开发和调用都很方便#xff0c;也是被大量采用的方式#xff0c;它可以让不同系统之间实现数据的交换和共享。 由于HTTP接口开放在互联网上#xff0c;所以我们就需要有一定的安全措施来保证接口…简介
HTTP接口是互联网各系统之间对接的重要方式之一使用HTTP接口开发和调用都很方便也是被大量采用的方式它可以让不同系统之间实现数据的交换和共享。 由于HTTP接口开放在互联网上所以我们就需要有一定的安全措施来保证接口安全。
个人觉得安全措施大体来看主要在两个方面
一方面就是如何保证数据在传输过程中的安全性另一个方面是数据已经到达服务器端服务器端如何识别数据如何不被攻击
HTTP API接口安全性演进如下
HTTP 完全开放 毫无安全可言HTTP 参数签名 基本安全HTTP 私钥签名公钥验签 (安全性高)HTTPS 参数签名 (安全性更高)HTTPS 私钥签名公钥验签 (最安全) 使用token进行用户身份认证
用户身份认证的流程图如下 具体说明如下
1、 用户登录时客户端请求接口传入用户名和密文的密码 2、 后台服务对用户身份进行验证。若验证失败则返回错误结果若验证通过则生成一个随机不重复的token并将其存储在redis中设置一个过期时间。 3、 用户身份校验通过后后台服务将生成的token返回客户端。 4、客户端请求后续其他接口时需要带上这个token。后台服务会统一拦截接口请求进行token有效性校验并从中获取用户信息供后续业务逻辑使用
数据加密
现在主流的加密方式有对称加密和非对称加密
对称加密对称密钥在加密和解密的过程中使用的密钥是相同的常见的对称加密算法有DESAES优点是计算速度快缺点是在数据传送前发送方和接收方必须商定好秘钥然后使双方都能保存好秘钥如果一方的秘钥被泄露那么加密信息也就不安全了非对称加密服务端会生成一对密钥私钥存放在服务器端公钥可以发布给任何人使用优点就是比起对称加密更加安全但是加解密的速度比对称加密慢太多了广泛使用的是RSA算法
两种方式各有优缺点而https的实现方式正好是结合了两种加密方式整合了双方的优点在安全和性能方面都比较好
数据加签名sign
常见的签名方式实现一般分为以下几个步骤 :
1 . 将所有(或者特殊)请求参数按特定规则排序在 Java 中可以使用 TreeMap 进行排序。
2 . 将请求参数按特定规则拼装为加密字符串
3 . 加密算法对加密字符串进行加密得到签名。
str参数1{参数1}参数2{参数2}……参数n{参数n}$key{用户密钥};
MD5.encrypt(str);时间戳机制
sign机制可以防止参数被篡改但无法防dos攻击第三方使用正确的参数不停请求服务器使之无法正常提供服务。因此还需要引入时间戳机制。 具体的操作为客户端在形成sign值时除了使用所有参数和token外再加一个发起请求时的时间戳。即
sign值来源 所有非空参数升序排序tokentimestamp
后端则需要根据当前时间和sign值的时间戳进行比较差值超过一段时间则不予放行。 long interval5*60*1000//超时时间
long clientTimerequest.getparameter(clientTime);
long serverTimeSystem.currentTimeMillis();
if(serverTime-clientTimeinterval){return new Response(超过处理时长)
}数据合法性校验
接口层对参数进行合法校验只有在数据是合法的情况下才会进行数据处理。
AppId机制
对应的对外提供的接口并不是谁都可以调用需要使用接口的用户需要在后台开通appid提供给用户相关的密钥在调用的接口中需要提供 appid密钥服务器端会进行相关的验证
限流
常用的限流算法有令牌桶和漏桶算法。
防止重复提交
对于一些重要的操作需要防止客户端重复提交的(如非幂等性重要操作)具体办法是当请求第一次提交时将sign作为key保存到redis并设置超时时间超时时间和Timestamp中设置的差值相同。
当同一个请求第二次访问时会先检测redis是否存在该sign如果存在则证明重复提交了接口就不再继续调用了。如果sign在缓存服务器中因过期时间到了而被删除了此时当这个url再次请求服务器时因token的过期时间和sign的过期时间一直sign过期也意味着token过期那样同样的url再访问服务器会因token错误会被拦截掉这就是为什么sign和token的过期时间要保持一致的原因。拒绝重复调用机制确保URL被别人截获了也无法使用如抓取数据。
接口参数私钥签名公钥验签
在客户端与服务端请求交互的过程中请求的数据容易被拦截并篡改比如在支付场景中请求支付金额为 1 元被拦截后篡改为 100 元由于没有防篡改校验导致多支付了金钱造成了用户损失。因此我们在接口设计时必须考虑防篡改校验加签、验签就是用来解决这个问题的。加签、验签是用来解决防篡改问题的。
相关概念
明文指没有经过加密的信息/数据。密文明文被加密算法加密之后会变成密文以确保数据安全。密钥是一种参数它是在明文转换为密文或将密文转换为明文的算法中输入的参数。密钥分为对称密钥与非对称密钥。加密将明文变成密文的过程。解密将密文还原为明文的过程。
对称加密、非对称加密
对称加密加密和解密使用相同密钥的加密算法。 非对称加密非对称加密算法中加密和解密用的不是同一个秘钥所以叫作非对称加密算法。在非对称加密算法每个用户都有两把钥匙一把公钥一把私钥。公钥是对外发布的所有人都看的到所有人的公钥私钥是自己保存每个人都只知道自己的私钥而不知道别人的。 非对称加密
什么是公钥私钥
公钥与私钥是成对存在的密钥如果用公钥对数据进行加密只有用对应的私钥才能解密。公钥就是公开的秘钥私钥就是要你自己保存好的秘钥。非对称加密算法需要有一对公私钥
如果用到的是非对称加密那么你和第三方之间就有两对公私钥各自持有对方的公钥和自己的私钥
加签验签
加签
签名主要包含摘要和非对称加密两部分内容首先对需要签名的数据进行摘要计算得到摘要值然后通过签名者的私钥对摘要值进行非对称加密即可得到签名结果。 一般情况下发送请求时会将数据和数字签名一起打包发送给接收方。 验签
接收方拿到原始报文和数字签名后用**「同一个Hash函数」**从报文中生成摘要A。另外用对方提供的公钥对数字签名进行解密得到摘要B对比A和B是否相同就可以得知报文有没有被篡改过。 互联网网上的这个图更容易理解一点 加密和解密
用该用户的公钥加密后只能该用户的私钥才能解密。这种情况下公钥是用来加密信息的确保只有特定的人用谁的公钥就是谁才能解密该信息。所以这种我们称之为加密和解密。
一、发送方RSAwithSHA、RSAwithMD5 1.对传输的报文进行摘要主要的算法有MD5和SHA 2.对摘要用自己的私钥进行加密生成签名一般用到的算法如RS 3.传输报文及签名
二、接收方 1.对接收到的报文用同样的算法进行摘要 2.用发送方的公钥对发送方的签名进行解密得到发送方的摘要 3.对比两份摘要看是否有不同以验证是否被篡改
常见加密相关算法简介
数据摘要算法是密码学算法中非常重要的一个分支它通过对所有数据提取指纹信息以实现数据签名、数据完整性校验等功能由于其不可逆性有时候会被用做敏感信息的加密。数据摘要算法也被称为哈希Hash算法或散列算法。
消息摘要算法的主要特征是加密过程不需要密钥并且经过加密的数据无法被解密只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。摘要可以比方为指纹消息摘要算法就是要得到文件的唯一职位
消息摘要算法对称加密算法非对称加密算法国密算法
消息摘要算法
相同的明文数据经过相同的消息摘要算法会得到相同的密文结果值。数据经过消息摘要算法处理得到的摘要结果值是无法还原为处理前的数据的。数据摘要算法也被称为哈希Hash算法或散列算法。消息摘要算法一般用于签名验签。
消息摘要算法主要分三类MDMessage Digest消息摘要算法、SHASecure Hash Algorithm安全散列算法和MACMessage Authentication Code消息认证码算法。 MD家族算法
MDMessage Digest消息摘要算法家族包括MD2MD4MD5。
MD2MD4MD5 计算的结果都是是一个128位即16字节的散列值用于确保信息传输完整一致。MD2的算法较慢但相对安全MD4速度很快但安全性下降MD5则比MD4更安全、速度更快。MD5被广泛应用于数据完整性校验、数据消息摘要、数据加密等。MD5可以被攻破对于需要高度安全性的数据专家一般建议改用其他算法如SHA-2。2004年证实MD5算法无法防止碰撞攻击因此不适用于安全性认证如SSL公开密钥认证或是数字签名等用途。
举个例子看看如何获取字符串的MD5值吧
public class MD5Test {public static void main(String[] args) throws UnsupportedEncodingException {String s 123;byte[] result getMD5Bytes(s.getBytes());StringBuilder stringBuilder new StringBuilder();for (byte temp : result) {if (temp 0 temp 16) {stringBuilder.append(0);}stringBuilder.append(Integer.toHexString(temp 0xff));}System.out.println(s ,MD5加密后: stringBuilder.toString());}private static byte[] getMD5Bytes(byte[] content) {try {MessageDigest md5 MessageDigest.getInstance(MD5);return md5.digest(content);} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);}}
}运行结果
123,MD5加密后:202cb962ac59075b964b07152d234b70ShA家族算法
SHASecure Hash Algorithm安全散列算法包括SHA-0、SHA-1、SHA-2(SHA-256,SHA-512,SHA-224,SHA-384等)、SHA-3。它是在MD算法基础上实现的与MD算法区别在于**「摘要长度」SHA 算法的摘要「长度更长安全性更高」**。 ❝ SHA-0发布之后很快就被NSA撤回因为含有会降低密码安全性的错误它是SHA-1的前身。SHA-1在许多安全协议中广为使用包括TLS、GnuPG、SSH、S/MIME和IPsec是MD5的后继者。SHA-2包括SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。它的算法跟SHA-1基本上相似目前还没有出现明显弱点。SHA-3是2015年正式发布由于对**「MD5出现成功的攻破」**以及对SHA-0和SHA-1出现理论上攻破的方法SHA-3应运而生。它与之前算法不同的是它是可替换的加密散列算法。 ❞ SHA-1、SHA-2(SHA-256,SHA-512,SHA-224,SHA-384)等算法是比较常用的我们来看看跟MD5的对比吧
算法类型摘要长度bits最大输入消息长度bits碰撞攻击bits性能示例(MiB/s)MD5128无限≤18发现碰撞335SHA-11602^64 − 163发现碰撞192SHA-2242242^64 − 1112139SHA-2562562^64 − 1128139SHA-3843842^128 − 1192154SHA-5125122^128 − 1256154
try {// 生成一个MD5加密计算摘要MessageDigest md MessageDigest.getInstance(MD5);// 计算md5函数md.update(str.getBytes());// digest()最后确定返回md5 hash值返回值为8为字符串。因为md5 hash值是16位的hex值实际上就是8位的字符// BigInteger函数则将8位的字符串转换成16位hex值用字符串来表示得到字符串形式的hash值return new BigInteger(1, md .digest()).toString(16);} catch (Exception e) {throw new Exception(MD5加密出现错误e.toString());}
}常用的签名算法 MAC算法家族
MAC算法 MACMessage Authentication Code消息认证码算法是带密钥的Hash函数。输入密钥和消息输出一个消息摘要。 它集合了MD和SHA两大系列消息摘要算法。
MD 系列算法: HmacMD2、HmacMD4 和 HmacMD5 SHA 系列算法HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384 和 HmacSHA512 。
对称加密算法
加密和解密使用**「相同密钥」**的加密算法就是对称加密算法。常见的对称加密算法有AES、3DES、DES、RC5、RC6等。 DES
数据加密标准英语Data Encryption Standard缩写为 DES是一种对称密钥加密块密码算法。 DES算法的入口参数有三个Key、Data、Mode。
Key: 7个字节共56位是DES算法的工作密钥Data: 8个字节64位是要被加密或被解密的数据Mode: 加密或解密。
3DES
三重数据加密算法英语Triple Data Encryption Algorithm又称3DESTriple DES是一种对称密钥加密块密码相当于是对每个数据块应用三次数据加密标准DES算法。
AES
AES高级加密标准英语Advanced Encryption Standard在密码学中又称Rijndael加密法是美国联邦政府采用的一种区块加密标准。
采用对称分组密码体制密钥长度为 128 位、 192 位、256 位分组长度128位相对于DES AES具有更好的 安全性、效率 和 灵活性。
非对称加密算法
非对称加密算法需要两个密钥公钥和私钥。公钥与私钥是成对存在的如果用公钥对数据进行加密只有用对应的私钥才能解密。主要的非对称加密算法有RSA、Elgamal、DSA、D-H、ECC。 RSA算法
RSA加密算法是一种非对称加密算法,广泛应用于加密和数字签名RSA算法原理两个大素数的乘积进行因式分解却极其困难因此可以将乘积公开作为加密密钥。RSA是被研究得最广泛的公钥算法从提出到现在经历了各种攻击的考验普遍认为是目前最优秀的公钥方案之一。
DSA
DSA(Digital Signature Algorithm,数字签名算法),也是一种非对称加密算法。DSA和RSA区别在DSA仅用于数字签名不能用于数据加密解密。其安全性和RSA相当但其性能要比RSA好。
ECC 算法
ECCElliptic Curves Cryptography椭圆曲线密码编码学基于椭圆曲线加密。Ecc主要优势是在某些情况下它比其他的方法使用更小的密钥比如RSA加密算法提供相当的或更高等级的安全级别。它的一个缺点是加密和解密操作的实现比其他机制时间长 (相比RSA算法该算法对CPU 消耗严重)。
国密算法
国密即国家密码局认定的国产密码算法。为了保障商用密码的安全性国家商用密码管理办公室制定了一系列密码标准即SM1SM2SM3SM4等国密算法。 SM1
SM1为对称加密算法加密强度为128位基于硬件实现。SM1的加密强度和性能与AES相当。
SM2
SM2主要包括三部分签名算法、密钥交换算法、加密算法SM2用于替换RSA加密算法基于ECC效率较低。
SM3
SM3即国产消息摘要算法。适用于商用密码应用中的数字签名和验证消息认证码的生成与验证以及随机数的生成。
SM4
SM4是一个分组算法用于无线局域网产品。该算法的分组长度为128比特密钥长度为128比特。加密算法与密钥扩展算法都采用32轮非线性迭代结构。解密算法与加密算法的结构相同只是轮密钥的使用顺序相反解密轮密钥是加密轮密钥的逆序。它的功能类似国际算法的DES。
RSA加签验签代码实现
下面使用用的是SHA-256作为摘要算法RSA作为签名验签算法如下
package com.demo.util;import com.alibaba.fastjson.JSONObject;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;public class RSAUtil {private static final String signature_algorithm SHA256withRSA; // 签名算法private static final String encryptAlgorithm RSA; // 加密算法private static final String decryptAlgorithm RSA; // 解密算法private static final String charset UTF-8;private static final int max_encrypt_block 234; //2048位rsa单次最大加密长度private static final int max_decrypt_block 256; //2048位rsa单次最大解密长度private static PublicKey sign_public_key null;private static PrivateKey sign_private_key null;private static PublicKey crypt_public_key null;private static PrivateKey crypt_private_key null;static {// 静态加载提高效率但是配置的修改都需要重启server才能生效// 对方base64后公钥字符串,用于验签String sign_pub_key_str MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnBYMjGWVjlWk3u7aXDtKmGghWV5glVTYFQ3ijelj3DwHB71jZQDKMnPkCeHMJk6iMJ04rakLbxiaMIhF/qx/RYfTvgrM9Y3ZNiK0PYTS2W8Iw2wjKDjOKO21NR4jl/PugOYDi6Ru6dmQjKPeGiDtJAPvqa7tyUyBrB0F4X/hFXMmTJ7TsBV4cTgzJy5iz9nntS6ccMUJ92xBimqLwDUTDeRtm1a2x3sIAOstCFOBsqyCXFWmOpElvGQcsMXvgw0DvNMGMpOEkqZoTt47Pp1FweOBqT6gT/q9xbAqFxTMUCI0XZan0mJ7MYBqA4ySqxg9J/uz4ppOEshwIDAQAB;// 己方base64后私钥字符串,用于签名String sign_pri_key_str MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCcFgyMZZWOVaTe7tpcO0qYaCFZXmCVVNgVDeKN6WPcPAcHvWNlAMoycQJ4cwmTqIwnTiv5qQtvGJowiEXrH9Fh9OCsz1jdk2IrQ9hNLZbwjDbCMoOM4o7bU35HiOX86A5gOLpG7p2ZCMo94aIO0kApru3JTIGsHQXhfH4Vf4z6ZMntOwFX7hxODMnLmLP2ee1LpxwxQn3bEGKaovANRMN5G2bX5rbHewgA6y0IU4GyrIJcVaY6kSW8ZBywxeDDQO80wb4z6k4SSpmhO3jsnUXB44GpPqBPr3FsCoXFMxQIjRdlqfSYnsxgGoDjJKrGD0n7Pin6k4SyHAgMBAAECggEASx1lTo94iLX4kPybgzVZcbzzB6Iekt7w2jkDZU4DK7KLo5Ll6W6W37buFG8wFapQQH4jNZO/lhcE60RGj2DRj/Wi6eAU8ZUC8lVFGcrs3mWxKAwpLVHEIvshH/hZOBj5bdNlOQ7lvHkD4skjtmhahutTLcOux9hzwxCa76ZPeeznN/JHI/CjI3J2JGRPDZmbcnezVdnJbQYY8K1YeuKIRFGkTh/sGIR1n3PDdxFPQSPv5VA/Ykd2IHXKTVoNhuozzxGIKbEThIvlBZo9CgXQ9AnZRELZRLagMUPUhbeeqpaTQYXMPAmziEN24TU9DfkhUl9rD3vO0CQKBgQDcBfxcw0awDwRTVbWZBKc01vnDhbWmt8GoJ2cITLvnR2FW8KgOFFMhCUjjmOgSBhGZnk8aKhMC1qQEd9e0VrmQ0IG0q8QlNf67CyHebVHBarcHcct68lyIRU498LfjUnbs3kswDrdR4zzEDMpQwYq6/TYKY513iiWwlygQwKBgQC1m7KYPzYj3wveErRgS26zngqVmXriWT8VFMAaqqs/hYlQ1Ho5U2e/tcZts4t1FfCgGPPM9vGkAc7Gn/sn6LSVQet1VRfc2IT5AcPOutwP8c7PpsOGoZYWWXJadhg1JqZo3rxGOhEQ1XWFXk/wX9d0Sllyu35sD0GRusXRQbQKBgBfIXdr5EK7/MIyBezurERfZFPStOTLBUtI4klDKFeNorEQ6AvOmosMOlaUeQw6UPGt/sCMjfO2bXJKuGL35kd1mDNa9fHqVLKa/4ngTizozCmIC3i2iDQl9nKUazyuxHHB/DDmZmIvdQlZBcfQPHd9UzFYiALFmyyKcwC4yaJZAoGAVWHqSaIOdjdk97x6kJ1HQKefAn0cXi/GAxRFwJJYBwGuFReesru5/2y8fJ5xuSJIUG3EfzpGbchxXdxLoJg9GN5ZSeZjLjkTVK7zdhMSuaeCp9v7UlouJ4OAU32rXp7ZRhzSL8JFG8EAC8AXnUyID6EZ2i3O17A2R8SuhtECgYBT/D3FZxSDvfNC3GFIRfIvsXMtAuM4MBvT6Z9ucyYluVORkEXcSRT3PcCTusUUEzN6gk2tgzhhHYY5O23LCsvFEy/nE8nkcDsqupvzLEces0OwRfUIj2KrrHkGGjNa5ioxu5ieO1VxoLu5HjP8shm/Oypfnk9A6x86Av3L3ScA;// 对方base64后公钥字符串,用于加密String crypt_pub_key_str MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnBYMjGWVjlWk3u7aXDtKmGghWV5glVTYFQ3ijelj3DwHB71jZQDKMnPkCeHMJk6iMJ04rakLbxiaMIhF/qx/RYfTvgrM9Y3ZNiK0PYTS2W8Iw2wjKDjOKO21NR4jl/PugOYDi6Ru6dmQjKPeGiDtJAPvqa7tyUyBrB0F4X/hFXMmTJ7TsBV4cTgzJy5iz9nntS6ccMUJ92xBimqLwDUTDeRtm1a2x3sIAOstCFOBsqyCXFWmOpElvGQcsMXvgw0DvNMGMpOEkqZoTt47Pp1FweOBqT6gT/q9xbAqFxTMUCI0XZan0mJ7MYBqA4ySqxg9J/uz4ppOEshwIDAQAB;// 己方base64后私钥字符串,用于解密String crypt_pri_key_str MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCcFgyMZZWOVaTe7tpcO0qYaCFZXmCVVNgVDeKN6WPcPAcHvWNlAMoycQJ4cwmTqIwnTiv5qQtvGJowiEXrH9Fh9OCsz1jdk2IrQ9hNLZbwjDbCMoOM4o7bU35HiOX86A5gOLpG7p2ZCMo94aIO0kApru3JTIGsHQXhfH4Vf4z6ZMntOwFX7hxODMnLmLP2ee1LpxwxQn3bEGKaovANRMN5G2bX5rbHewgA6y0IU4GyrIJcVaY6kSW8ZBywxeDDQO80wb4z6k4SSpmhO3jsnUXB44GpPqBPr3FsCoXFMxQIjRdlqfSYnsxgGoDjJKrGD0n7Pin6k4SyHAgMBAAECggEASx1lTo94iLX4kPybgzVZcbzzB6Iekt7w2jkDZU4DK7KLo5Ll6W6W37buFG8wFapQQH4jNZO/lhcE60RGj2DRj/Wi6eAU8ZUC8lVFGcrs3mWxKAwpLVHEIvshH/hZOBj5bdNlOQ7lvHkD4skjtmhahutTLcOux9hzwxCa76ZPeeznN/JHI/CjI3J2JGRPDZmbcnezVdnJbQYY8K1YeuKIRFGkTh/sGIR1n3PDdxFPQSPv5VA/Ykd2IHXKTVoNhuozzxGIKbEThIvlBZo9CgXQ9AnZRELZRLagMUPUhbeeqpaTQYXMPAmziEN24TU9DfkhUl9rD3vO0CQKBgQDcBfxcw0awDwRTVbWZBKc01vnDhbWmt8GoJ2cITLvnR2FW8KgOFFMhCUjjmOgSBhGZnk8aKhMC1qQEd9e0VrmQ0IG0q8QlNf67CyHebVHBarcHcct68lyIRU498LfjUnbs3kswDrdR4zzEDMpQwYq6/TYKY513iiWwlygQwKBgQC1m7KYPzYj3wveErRgS26zngqVmXriWT8VFMAaqqs/hYlQ1Ho5U2e/tcZts4t1FfCgGPPM9vGkAc7Gn/sn6LSVQet1VRfc2IT5AcPOutwP8c7PpsOGoZYWWXJadhg1JqZo3rxGOhEQ1XWFXk/wX9d0Sllyu35sD0GRusXRQbQKBgBfIXdr5EK7/MIyBezurERfZFPStOTLBUtI4klDKFeNorEQ6AvOmosMOlaUeQw6UPGt/sCMjfO2bXJKuGL35kd1mDNa9fHqVLKa/4ngTizozCmIC3i2iDQl9nKUazyuxHHB/DDmZmIvdQlZBcfQPHd9UzFYiALFmyyKcwC4yaJZAoGAVWHqSaIOdjdk97x6kJ1HQKefAn0cXi/GAxRFwJJYBwGuFReesru5/2y8fJ5xuSJIUG3EfzpGbchxXdxLoJg9GN5ZSeZjLjkTVK7zdhMSuaeCp9v7UlouJ4OAU32rXp7ZRhzSL8JFG8EAC8AXnUyID6EZ2i3O17A2R8SuhtECgYBT/D3FZxSDvfNC3GFIRfIvsXMtAuM4MBvT6Z9ucyYluVORkEXcSRT3PcCTusUUEzN6gk2tgzhhHYY5O23LCsvFEy/nE8nkcDsqupvzLEces0OwRfUIj2KrrHkGGjNa5ioxu5ieO1VxoLu5HjP8shm/Oypfnk9A6x86Av3L3ScA;try {KeyFactory keyFactory KeyFactory.getInstance(RSA);sign_public_key keyFactory.generatePublic(new X509EncodedKeySpec(Base64Utils.decodeFromString(sign_pub_key_str))); // 用于验签sign_private_key keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64Utils.decodeFromString(sign_pri_key_str))); // 用于签名crypt_public_key keyFactory.generatePublic(new X509EncodedKeySpec(Base64Utils.decodeFromString(crypt_pub_key_str))); // 用于加密crypt_private_key keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64Utils.decodeFromString(crypt_pri_key_str))); // 用于解密} catch (Exception e) {//日志记录}}/*** 签名* param param* return*/public static String sign(String param) {try {if (sign_private_key null) {throw new RuntimeException(私钥未初始化);}Signature signature Signature.getInstance(signature_algorithm);signature.initSign(sign_private_key);signature.update(param.getBytes(charset));return Base64Utils.encodeToString(signature.sign());} catch (Exception e) {throw new RuntimeException(签名异常, e);}}/*** 加密* param param* return*/public static String encrypt(String param) {if (crypt_public_key null) {throw new RuntimeException(公钥未初始化);}if (StringUtils.isEmpty(param)) {throw new IllegalArgumentException(待加密数据为空);}try (ByteArrayOutputStream out new ByteArrayOutputStream()) {Cipher cipher Cipher.getInstance(encryptAlgorithm);cipher.init(Cipher.ENCRYPT_MODE, crypt_public_key);byte[] data param.getBytes(charset);int inputLen data.length;int offSet 0;byte[] cache;int i 0;// 对数据分段加密while (inputLen - offSet 0) {if (inputLen max_encrypt_block offSet) {cache cipher.doFinal(data, offSet, max_encrypt_block);} else {cache cipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i;offSet i * max_encrypt_block;}return Base64Utils.encodeToString(out.toByteArray());} catch (Exception e) {throw new RuntimeException(加密异常, e);}}/*** 验签* param param* param sign* return*/public static boolean veriSign(String param, String sign) {try {if (sign_public_key null) {throw new RuntimeException(公钥未初始化);}Signature signature Signature.getInstance(signature_algorithm);signature.initVerify(sign_public_key);signature.update(param.getBytes(charset));return signature.verify(Base64Utils.decodeFromString(sign));} catch (Exception e) {throw new RuntimeException(验签失败, e);}}/*** 解密* param param* return*/public static String decrypt(String param) {if (crypt_private_key null) {throw new RuntimeException(私钥未初始化);}if (StringUtils.isEmpty(param)) {throw new IllegalArgumentException(待解密数据为空);}try (ByteArrayOutputStream out new ByteArrayOutputStream()) {Cipher cipher Cipher.getInstance(decryptAlgorithm);cipher.init(Cipher.DECRYPT_MODE, crypt_private_key);byte[] data Base64Utils.decodeFromString(param);int inputLen data.length;int offSet 0;byte[] cache;int i 0;// 对数据分段解密while (inputLen - offSet 0) {if (inputLen max_decrypt_block offSet) {cache cipher.doFinal(data, offSet, max_decrypt_block);} else {cache cipher.doFinal(data, offSet, inputLen - offSet);}i;out.write(cache, 0, cache.length);offSet i * max_decrypt_block;}return new String(out.toByteArray(), charset);} catch (Exception e) {throw new RuntimeException(解密处理异常, e);}}public static void main(String[] args){
// generateKey();
// requestDemo();serverDemo();}/*** 发起请求*/private static void requestDemo() {try {String param new JSONObject().fluentPut(name, 张三).toJSONString();String data encrypt(param);String sign sign(data);JSONObject jsonObject new JSONObject().fluentPut(sign, sign).fluentPut(data, data);System.out.println(加密后jsonObject.toJSONString());HttpPost httpPost new HttpPost(url);httpPost.setEntity(new StringEntity(jsonObject.toJSONString(), application/json, utf-8));HttpClient httpClient HttpClientBuilder.create().build();httpClient.execute(httpPost);((CloseableHttpClient) httpClient).close();} catch (IOException ignore) {}}/*** 服务方* return*/private static String serverDemo() {// http获取请求头, 请求体String requestBody {\data\:\hlnWYqUGXLgZVPifPrVtEp//4GY6t6GM03m1exbDFhsnYGDyADlOREBDsOHvqgfZ3lPhZCKiva0tK5zgSTfbpXPymQxtOhx5x1PekLxx2G/myK74lErC5Vj5OY5oyI12o07TWbaqENATYldViCGf5pZMs2LgYYLpfdVKoth2Xs80MEU/2RzivGp5f1CJSTaG5Vz4cFXWVqorhG3/9Kt1d1sSv8VYaM0fREx1TBKzEzTq1GtEMW/9eRPMj8YY5W2vo1JsdhgfzoAC8m/pdBbQ493ePJzMpdRI/Zt/bbnZVkGw5YYpI7saTrWDxjtpEeMaZ9RHyMWrusacAD1SA\,\sign\:\gIC9PdGO99e4IXDP06LRz4pktULp5nQ50lI3nTL0pi8N9yjG6laODmeOzTsSbsoSGeGuTaikaqGBTkN2Fmj5923K8jTJ/A0bFCuNlIpVaoTtC6r8S7J/whW63EPJ3JRWWjWZ2QWWWYNMofGLVZ4veps8Q02zyrW0pQh0Sc5TykaOOrX3eu0wcXF4mep5CLutQnDCVBWBwTn1D3Lfhc42UsuSKvPpteCTOwI2mJ/m8swJg0lMvt/iDVBOSx55ItVEbg3OVmNvki4DTBsGuhy6inPQ5zF4S/SDVqseHL63g6OAb8EX/fW9GleFBuzcrs1zkYF4Gd0fUXm1N/uFsHqQ\};// 接收请求获取参数JSONObject requestParams JSONObject.parseObject(requestBody);/*取参数及签名*/String data requestParams.getString(data);String sign requestParams.getString(sign);/*验签*/boolean f veriSign(data, sign);if (f) { // 验签通过才需要解密,否则认为非法请求/*解密*/String dec decrypt(data);System.out.println(解密后dec);/*业务逻辑*/JSONObject businessResult doBusiness(dec);/*加密*/String responseParam encrypt(businessResult.toJSONString());/*签名*/String responseSign sign(responseParam);MapString, String response new HashMap(2);response.put(data, responseParam);response.put(sign, responseSign);/*返回*/return JSONObject.toJSONString(response);}else {return null;}}private static JSONObject doBusiness(String dec) {/*响应结果*/return new JSONObject();}/*** 密钥生成*/private static void generateKey() {try {KeyPairGenerator keyPairGen KeyPairGenerator.getInstance(encryptAlgorithm);keyPairGen.initialize(2048);KeyPair keyPair keyPairGen.generateKeyPair();RSAPublicKey publicKey (RSAPublicKey) keyPair.getPublic();RSAPrivateKey privateKey (RSAPrivateKey) keyPair.getPrivate();System.out.println(privateKey: Base64Utils.encodeToString(privateKey.getEncoded()));System.out.println(publicKey: Base64Utils.encodeToString(publicKey.getEncoded()));} catch (NoSuchAlgorithmException ignore) {}}}