密码安全

摘要加密

摘要是哈希值,我们通过散列算法比如MD5算法就可以得到这个哈希值。摘要只是用于验证数据完整性和唯一性的哈希值,不管原始数据是什么样的,得到的哈希值都是固定长度的。 不管原始数据是什么样的,得到的哈希值都是固定长度的,也就是说摘要并不是原始数据加密后的密文,只是一个验证身份的令牌。所以我们无法通过摘要解密得到原始数据。

MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函 数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由 美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。这套 算法的程序在 RFC 1321 标准中被加以规范。1996年后该算法被证实存在弱点,可以被加以破解,对于 需要高度安全性的数据,专家一般建议改用其他算法,如SHA-2。2004年,证实MD5算法无法防止碰撞 (collision),因此不适用于安全性认证,如SSL公开密钥认证或是数字签名等用途。 MD5存在一个缺陷,只要明文相同,那么生成的MD5码就相同,于是攻击者就可以通过撞库的方式 来破解出明文。加盐就是向明文中加入指定字符,主要用于混淆用户、并且增加MD5撞库破解难度,这样一来即使撞库破解,知道了明文,但明文也是混淆了的,真正需要用到的数据也需要从明文中摘取, 摘取范围、长度、摘取方式都是个谜,如此一来就大大增加了暴力破解的难度,使其几乎不可能破解。

摘要加密算法

  1. MD5算法法(MD2 、MD4、MD5)
  2. SHA算法(SHA1、SHA256、SHA384、 SHA512)
  3. HMAC算法

特点

  1. 任何数据加密,得到的密文长度固定。
  2. 密文是无法解密的(不可逆)。

验签

验签其实就是签名验证,MD5加密算法经常用于签名安全验证。疑问:要是密文也一起改了再传过去呢?

代码示例

import org.apache.commons.codec.digest.DigestUtils;

public class MD5Util {

/**
* MD5方法
*
* @param text 明文
* @return 密文
* @throws Exception
*/
public static String md5(String text) throws Exception {
//加密后的字符串
String encode = DigestUtils.md5Hex(text);
return encode;
}

/**
* MD5方法
*
* @param text 明文
* @param key 盐
* @return 密文
* @throws Exception
*/
public static String md5(String text, String key) throws Exception {
//加密后的字符串
String encode = DigestUtils.md5Hex(text + key);
return encode;
}

/**
* MD5验证方法
*
* @param text 明文
* @param key 密钥/盐
* @param md5 密文
* @return true/false
* @throws Exception
*/
public static boolean verify(String text, String key, String md5) throws Exception {
//根据传入的密钥进行验证
String md5Text = md5(text, key);
return md5Text.equalsIgnoreCase(md5);
}

public static void main(String[] args) throws Exception {
String test = "admin";
String key = "tiger";
String md5 = "bcf918bd662986b3bcab0f9a32a21e1d";
String md5Str = md5(test, key);
System.out.println(md5Str);
boolean passOrNot = verify(test, key, md5);
System.out.println(passOrNot);
}
}

Base64

Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印 字符来表示二进制数据的方法。

解决编码问题

代码示例

import java.util.Base64;

public class Base64Util {

/***
* 普通解密操作
* @param encodedText:密文
* @return
*/
public static byte[] decode(String encodedText) {
final Base64.Decoder decoder = Base64.getDecoder();
return decoder.decode(encodedText);
}

/***
* 普通加密操作
* @param data
* @return
*/
public static String encode(byte[] data) {
final Base64.Encoder encoder = Base64.getEncoder();
return encoder.encodeToString(data);
}

/***
* 解密操作
* @param encodedText
* @return
*/
public static byte[] decodeURL(String encodedText) {
final Base64.Decoder decoder = Base64.getUrlDecoder();
return decoder.decode(encodedText);
}

/***
* 加密操作
* @param data
* @return
*/
public static String encodeURL(byte[] data) {
final Base64.Encoder encoder = Base64.getUrlEncoder();
return encoder.encodeToString(data);
}

public static void main(String[] args) throws Exception {
String str = "今天的饭真好吃啊!明天还来!";

// 加密
String encode = encode(str.getBytes("UTF-8"));
// 解密
byte[] decode = decode(encode);
// 字节数组 -》字符串
String text = new String(decode, "UTF-8");
System.out.println("密文:" + encode);
System.out.println("明文:" + text);

// URL
// 加密
String encodeURL = encodeURL(str.getBytes("UTF-8"));
// 解密
byte[] decodeURL = decodeURL(encodeURL);
// 字节数组 -》字符串
String textURL = new String(decodeURL, "UTF-8");
System.out.println("密文:" + encodeURL);
System.out.println("明文:" + textURL);
}
}

对称加密AES

典型的对称加密算法有AES、DES、3DES,但AES加密算法的安全性要高于DES和3DES,所以AES 已经成为了主要的对称加密算法。

AES加密算法就是众多对称加密算法中的一种,它的英文全称是Advanced Encryption Standard, 翻译过来是高级加密标准,它是用来替代之前的DES加密算法的。 要理解AES的加密流程,会涉及到AES加密的五个关键词,分别是:分组密码体制、Padding、密 钥、初始向量IV和四种加密模式

代码示例

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;

public class AESUtil {

/**
* AES加密/解密
*
* @param buffer:密文/明文
* @param secretKey:秘钥
* @param mode:加密/解密模式 1 加密 2 解密
* @return
*/
public static byte[] encryptAndDecrypt(byte[] buffer, String secretKey, Integer mode) throws Exception {
// 1、加载加密解密算法处理对象(包含算法、秘钥管理)
Security.addProvider(new BouncyCastleProvider());

// 2、根据不同算法创建秘钥 1)秘钥的字节数组 2)加密算法
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes("UTF-8"), "AES");

// 3、设置加密模式(无论是加密还是解析,模式一致)
// 1)、AES/ECB/KPS7Padding 设置算法
// 2)、指定算法库对象
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
// 4、初始化加密配置
cipher.init(mode, secretKeySpec);
// 5、执行加密/解密
return cipher.doFinal(buffer);
}

/***
* 加密解密测试
* 密钥:128(16)、192(24)、256(32)
*/
public static void main(String[] args) throws Exception {
// 明文
String plainText = "SpringCloud Alibaba";
// 128bit 16位密钥
String secretKey = "1234567890123456";
// 将128bit 16位密钥 -》 256bit 32位密钥
secretKey = MD5Util.md5(secretKey);
System.out.println("明文:" + plainText);
System.out.println("密钥:" + secretKey);

// 加密
byte[] bytes = encryptAndDecrypt(plainText.getBytes("UTF-8"), secretKey, 1);
// 编码
String encodeStr = Base64Util.encode(bytes);
System.out.println("密文:" + encodeStr);

//解密 ->解码Base64->解密
byte[] decodeStr = encryptAndDecrypt(Base64Util.decode(encodeStr), secretKey, 2);
System.out.println("解密后数据:" + new String(decodeStr, "UTF-8"));
}
}

微信支付-Native

接口文档

​https://pay.weixin.qq.com/wiki/doc/api/index.html​

流程说明

  1. 商户后台系统根据用户选购的商品生成订单。
  2. 用户确认支付后调用微信支付【统一下单API】生成预支付交易;
  3. 微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。
  4. 商户后台系统根据返回的code_url生成二维码。
  5. 用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。
  6. 微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。
  7. 用户在微信客户端输入密码,确认支付后,微信客户端提交授权。
  8. 微信支付系统根据用户授权完成支付交易。
  9. 微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
  10. 微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。
  11. 未收到支付通知的情况,商户后台系统调用【查询订单API】。
  12. 商户确认订单已支付后给用户发货。

开发步骤

  1. 过修改官方wxpay-sdk源码,将抽象方法的修饰符从默认修改为public, 然后重新打包到本地或者私服
import com.github.wxpay.sdk.IWXPayDomain;
import com.github.wxpay.sdk.WXPayConfig;
import com.github.wxpay.sdk.WXPayConstants;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

@Component
public class WeixinPayConfig extends WXPayConfig {

//微信支付信息
@Value("${payconfig.weixin.appId}")
private String appId; //应用ID
@Value("${payconfig.weixin.mchID}")
private String mchID; //商户号
@Value("${payconfig.weixin.key}")
private String key; //秘钥
@Value("${payconfig.weixin.notifyUrl}")
private String notifyUrl; //回调地址
@Value("${payconfig.weixin.certPath}")
private String certPath; //证书路径
//证书字节数组
private byte[] certData;

@Override
public String getAppID() {
return this.appId;
}

@Override
public String getMchID() {
return this.mchID;
}

@Override
public String getKey() {
return this.key;
}

/***
* 获取商户证书内容
* @return
*/
@Override
public InputStream getCertStream() {
/****
* 加载证书
*/
if (certData == null) {
synchronized (WeixinPayConfig.class) {
try {
if (certData == null) {
File file = new File(certPath);
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
return certBis;
}

/***
* 获取WXPayDomain, 用于多域名容灾自动切换
* @return
*/
@Override
public IWXPayDomain getWXPayDomain() {
// 这个方法需要这样实现, 否则无法正常初始化WXPay
IWXPayDomain iwxPayDomain = new IWXPayDomain() {
@Override
public void report(String domain, long elapsedTimeMillis, Exception ex) {

}

@Override
public DomainInfo getDomain(WXPayConfig config) {

return new DomainInfo(WXPayConstants.DOMAIN_API, true);
}
};
return iwxPayDomain;
}
}
  1. 微信支付\证书和秘钥中的证书以及秘钥配置导入到 mall-pay-service 工程中,如果是php开发,采用pem证书,如果是java开发采用p12证书
  2. 创建 WXPay 的实例并交给Spring容器管理
import com.github.wxpay.sdk.WXPay;
import com.gupaoedu.vip.mall.pay.config.WeixinPayConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@MapperScan(basePackages = {"com.tiger.mall.pay.mapper"})
public class MallPayApplication {

public static void main(String[] args) {
SpringApplication.run(MallPayApplication.class, args);
}

/****
* 微信支付SDK对象
* @param weixinPayConfig
* @return
* @throws Exception
*/
@Bean
public WXPay wxPay(WeixinPayConfig weixinPayConfig) throws Exception {
return new WXPay(weixinPayConfig);
}
}

微信退款