«Эта статья участвовала в мероприятии Haowen Convocation Order, щелкните, чтобы просмотреть:Двойные заявки на внутреннюю и внешнюю стороны, призовой фонд в 20 000 юаней ждет вас, чтобы бросить вызов!"
предисловие
Скоро стартует новый проект.Так как проект предполагает стыковку интерфейса со сторонними производителями, то есть требования к безопасности интерфейса.Посмотрим как написать стандартный интерфейс.
Как обеспечить безопасность данных при передаче по интерфейсу
Чтобы обеспечить безопасность данных, первое, о чем может подумать каждый, — зашифровать контент. Существует два основных способа шифрования: симметричное шифрование и асимметричное шифрование.
1. Симметричное шифрование
Давайте посмотрим на картинку вместе
Видно, что на приведенном выше рисунке используется метод шифрования криптосистемы с одним ключом, и один и тот же ключ может использоваться для одновременного шифрования и дешифрования информации.Этот метод шифрования называется симметричным шифрованием, также известным как одиночное шифрование. - ключевое шифрование. Симметричное шифрование имеет много видов алгоритмов и благодаря своей высокой эффективности широко используется в основе многих протоколов шифрования. Стойкость симметричного шифрования зависит от размера ключа, чем больше ключ, тем сложнее его взломать, но процесс одновременного шифрования и дешифрования занимает больше времени. Обычно используемые алгоритмы симметричного шифрования: DES, 3DES, TDEA, Blowfish, RC2, RC4, RC5, IDEA, SKIPJACK и т. д. Давайте рассмотрим пример симметричного шифрования с использованием DES.
Первая часть — шифрование
/**
* 加密
* @param data 待加密内容
* @param secretKey 密钥
* @return
*/
public static byte[] encrypt(byte[] data, String secretKey) {
try {
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(secretKey.getBytes());
// 创建一个密匙工厂,然后用它把DESKeySpec转换成
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance("DES");
// 用密匙初始化Cipher对象,ENCRYPT_MODE用于将 Cipher 初始化为加密模式的常量
cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
// 现在,获取数据并加密
return cipher.doFinal(data);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
Затем идет часть расшифровки
/**
* 解密
* @param src
* @param secretKey
* @return
* @throws Exception
*/
public static byte[] decrypt(byte[] src, String secretKey) throws Exception {
// DES算法要求有一个可信任的随机数源
SecureRandom random = new SecureRandom();
// 创建一个DESKeySpec对象
DESKeySpec desKey = new DESKeySpec(secretKey.getBytes());
// 创建一个密匙工厂,返回实现指定转换的
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
// 将DESKeySpec对象转换成SecretKey对象
SecretKey secureKey1 = keyFactory.generateSecret(desKey);
// 获取Cipher对象
Cipher cipher = Cipher.getInstance("DES");
// 初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, secureKey1, random);
// 解密
return cipher.doFinal(src);
}
Далее мы тестируем
public static void main(String[] args) throws Exception {
// 待加密内容
String str = "https://juejin.cn/user/2084329778071479";
// 密钥
String secretKey = "xtianyaa";
byte[] encrypt = encrypt(str.getBytes(), secretKey);
System.out.println("加密前:" +str);
System.out.println("加密后:" + new String(encrypt));
// 解密
byte[] decrypt = decrypt(encrypt, secretKey);
System.out.println("解密后:" + new String(decrypt));
}
выходной результат
加密前:https://juejin.cn/user/2084329778071479
加密后:SA(��j�tj��G/�[M(��y�݇t.�7z"D�3�<
解密后:https://juejin.cn/user/2084329778071479
2. Асимметричное шифрование
Алгоритмы асимметричного шифрования требуют двух ключей:公钥
и私钥
. Открытый ключ и закрытый ключ представляют собой пару. Если данные зашифрованы с помощью открытого ключа, их можно расшифровать только с помощью соответствующего закрытого ключа. Поскольку для шифрования и дешифрования используются два разных ключа, этот алгоритм называется алгоритмом асимметричного шифрования. Основной процесс алгоритма асимметричного шифрования для реализации обмена конфиденциальной информацией состоит в следующем: Сторона А генерирует пару ключей и раскрывает открытый ключ, а другие роли (Сторона Б), которым необходимо отправить информацию Стороне А, используют этот ключ (Сторона открытый ключ А) для сопряжения Конфиденциальная информация шифруется и затем отправляется Стороне А; Затем Сторона А расшифровывает зашифрованную информацию с помощью своего личного ключа. Когда Сторона А хочет ответить Стороне Б, напротив, она использует открытый ключ Стороны Б для шифрования данных. Точно так же Сторона Б использует свой собственный закрытый ключ для расшифровки. Давайте посмотрим на разницу между асимметричным шифрованием и симметричным шифрованием.
Характеристики асимметричной криптосистемы: сила алгоритма сложна, а безопасность зависит от алгоритма и ключа, но из-за сложности алгоритма скорость шифрования и дешифрования не такая высокая, как у симметричного шифрования. и расшифровка. В системе симметричного шифрования есть только один ключ, и он не является публичным, и если вы хотите его расшифровать, вы должны сообщить ключ другой стороне. Следовательно, чтобы обеспечить его безопасность, необходимо обеспечить безопасность ключа.Система асимметричного ключа имеет два ключа, один из которых является открытым, так что нет необходимости передавать ключ другой стороны, как симметричный ключ. Таким образом, безопасность намного выше.
Основными алгоритмами реализации асимметричного шифрования являются: RSA, Elgamal, алгоритм ранца, Rabin, D-H, ECC (алгоритм шифрования на эллиптических кривых), наиболее широко используетсяRSA
алгоритм.
как доказать, что ты ты
Еще одна важная часть интерфейса API заключается в том, что签名
, по подписи мы можем узнать, был ли подделан вызывающий интерфейс. Давайте взглянем на реализацию подписи интерфейса.
/**
*
* @param appId 调用方的ID,唯一
* @param appKey 调用方APP_KEY,每个调用方固定一个字符串,唯一
* @param sign 签名,appId+appKey + request秘钥(不参与接口参数传递,本地保存) + 时间戳(以long类型的字符串.格式:yyyyMMddHHmmss),经过MD5加密后生成的串(字母小写)
* @param requestTime 时间戳(以long类型的字符串)
* @param type 数据类型
* @param data 数据内容 使用非对称加密,接口调用者用公钥加密,接收后用私钥进行解密
* @return
*/
@PostMapping("/system_api")
@Limit(key = "get_system_api", period = 60, count = 10, name = "主屏接口数据采集", prefix = "limit")
public String systemApi(@RequestHeader("APP_ID") String appId,
@RequestHeader("APP_KEY") String appKey,
@RequestHeader("TOKEN") String sign,
@RequestHeader("TIMESTAMP") String requestTime,
@RequestParam String type, @RequestBody String data){
String checkInfo = paramsCheck(appId,appKey,sign,requestTime);
if(!SUCCESS.equals(checkInfo)){
return checkInfo;
}
return SUCCESS;
}
Видно, что знак генерируется после шифрования MD5 через appId+appKey + запрос секретного ключа + временная метка, когда мы получим знак, мы проверим его по соответствующим параметрам.
**
* 根据接口请求的参数进行身份验证
* @param appId
* @param appKey
* @param sign
* @param requestTime
*/
private String paramsCheck(String appId, String appKey, String sign, String requestTime) {
AppConfig appConfig = appConfigService.getAppConfig(appId);
String errorInfo = SUCCESS;
//1、判断key是否正确
if (!appKey.equals(appConfig.getAppKey())){
errorInfo = "500";
}
//2、拼接字符串
String key = appId+appConfig.getAppKey()+appConfig.getAppSecret()+requestTime;
//3、根据appId+appKey+AppSecret+requestTime,经过md5后, 生成签名
String newSign = DigestUtils.md5DigestAsHex(key.getBytes());
//4、判断签名是否经过篡改
if(!sign.equals(newSign)){
errorInfo = "500";
}
//5、判断请求时间是否异常,防止使用过期签名进行身份认证
Date date = null;
try {
date = new SimpleDateFormat("yyyyMMddHHmmss").parse(requestTime);
} catch (ParseException e) {
log.error(e.getMessage());
}
long second = 0;
if (date != null) {
second = getDatePoor(new Date(),date);
}else{
errorInfo = "TIME IS NULL";
}
if(second>TIME_OUT){
errorInfo = "TIME OUT";
}
return errorInfo;
}
Видно, что мы добавили поле метки времени при создании знака, главным образом для того, чтобы они не могли напрямую использовать полученный признак, и после добавления метки времени срок ее действия может истечь.
Суммировать
Что ж, прочитав это, я считаю, что все знают, как обеспечить безопасность интерфейса при написании OPEN API, и я надеюсь, что это будет полезно для всех.