当前位置: 首页 > news >正文

微服务实战系列之API加密

前言

随着一阵阵凛冽寒风的呼啸,新的年轮不知不觉滚滚而来。故事随着2023的远去,尘封于案底;希望迎着新年,绽放于枝头。在2024新岁启航,扬帆破浪之时,让烦恼抛洒于九霄,让生机蓬勃于朝朝暮暮。

2024,博主祝福各位盆友,书写新的人生,获得新的希望!

在这里插入图片描述

新年开篇第一博,希望带给各位盆友新的收获。“踏破铁鞋无觅处,博主文章可驻足”,此刻的我,不禁沾沾自喜…

废话少叙,言归正传。今日,我们开始新的旅程,微服务实战系列继续乘势而上,博主该谈谈API安全的“那些事儿”了。


一、API

什么是API?请先了解来自百度百科的定义:

应用程序编程接口(Application Programming Interface,简称:API),是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。——百度百科

通俗讲,就是一个面向开发者使用的接口或程序。既然是API,那么一定是具备某些能力,所谓“麻雀虽小五脏俱全”

在这里插入图片描述

但凡是API,必定涉及数据安全问题。因为API本质是完成“以数易数”的过程。这个过程中一般会遇到诸如以下安全问题:

1、数据泄密

我们说数据有多“敏感”,责任有多严重,这力不再赘述。

2、数据劫持

API请求过程中,被黑客劫持数据报文后,后果不堪设想。

3、恶意调用

恶意调用其实是饱和攻击的一种,直至系统服务瘫痪,会造成严重的经济损失。

二、API安全

针对以上API安全风险,我们显然已具备针对性的防范措施和能力。
具体有:

  1. 采用HTTPS协议传输
  2. 数据加密
  3. 数据签名
  4. 限流降级

以上措施,均可有效提高API的风险壁垒,“防火于未燃”。而今天博主重点讲一讲其中的第2点,即数据加密是如何完成的。其他内容可回看博主历史文章,均有涉猎。

三、API数据加密

首先,API数据加密,是针对传输过程中的请求报文和返回报文而言的。API的请求过程,其实是一次两端(C/S)通信的过程,所以涉及数据的传输安全。

如何保障传输安全,加密是一个不错的选择。实现的核心逻辑,可参考下图:
在这里插入图片描述
基于SpringBoot的开发框架,我们通常选择AOP,以注解的方式,完成以上逻辑实现。接下来,博主提供相关实现代码,以供参考。

1、引入依赖

本文加密机制,使用了jasypt-spring-boot-starter,务必添加以下依赖:

<dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>3.0.5</version>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

2、定义注解

首先需要准备2个注解,分别如下:

注解名称注解简介
Encrypt用于请求体的加密注解
Decrypt用于返回体的解密注解
2.1 Encrypt 代码参考:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;//加密
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Encrypt {
}
2.2 Decrypt 代码参考:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;//解密
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.PARAMETER})
public @interface Decrypt {
}

3、定义AOP

3.1 返回体加密Advice(EncryptResponse)

一句话总结:通过将返回体(response)转换为String,实现数据加密。

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import cn.hutool.json.JSONUtil;/*** @description:加密* @date 2024/01/06 14:02*/
@ControllerAdvice
public class EncryptResponse implements ResponseBodyAdvice<Object> {public EncryptResponse() {}public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {return returnType.hasMethodAnnotation(Encrypt.class);}@Overridepublic Object beforeBodyWrite(Object res, MethodParameter returnType,MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType,ServerHttpRequest request, ServerHttpResponse response) {try {String content =  JSONUtil.toJsonStr(JSONUtil.parseObj(res, false));//加密算法,自选,可以是AES,可以是RSA...String encryptResBody = AesEncryptUtils.encrypt(content, Constants.AESKEY);return encryptResBody;} catch (Exception e) {e.printStackTrace();}return res;	}
}
3.2 请求体解密Advice(DecryptRequest)

一句话总结:通过将请求体(request)转换为字节流,实现数据解密。

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;/*** @description:解密* @date 2024/01/06 14:35*/
@ControllerAdvice
public class DecryptRequest extends RequestBodyAdviceAdapter {public DecryptRequest() {}public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {return methodParameter.hasMethodAnnotation(Decrypt.class) || methodParameter.hasParameterAnnotation(Decrypt.class);}public HttpInputMessage beforeBodyRead(final HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {byte[] body = new byte[inputMessage.getBody().available()];inputMessage.getBody().read(body);try {//解密算法,自选,可以是AES,可以是RSA...byte[] decrypt = AesEncryptUtils.decrypt(new String(body,Constants.UTF8),Constants.AESKEY).getBytes();final ByteArrayInputStream bais = new ByteArrayInputStream(decrypt);return new HttpInputMessage() {public InputStream getBody() throws IOException {return bais;}public HttpHeaders getHeaders() {return inputMessage.getHeaders();}};} catch (Exception e) {e.printStackTrace();return super.beforeBodyRead(inputMessage, parameter, targetType, converterType);}}
}

4、使用注解

完成以上注解实现, 即可满足API的加密需求了。

如何使用?那不就简单了…直接在Controller的接口中使用注解即可,可参考:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;/*** @description: API加密* @date 2024/01/06 15:58*/
@Slf4j
@RestController
@RequestMapping("/api")
public class TestController
{@Encrypt@Decrypt@PostMapping("/getData")public Object getData(@RequestBody String input){// TODO}
}

四、AES算法

本文使用的加密算法是基于AES完成,博主分享大家(已解决已知问题,比如长度不足128,支持分段),供参考:


import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** AES加解密*/
public class AesEncryptUtils {private static Logger log = LoggerFactory.getLogger(AesEncryptUtils.class);private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";private static final String KEY = "1234567890abcdef";//可支持128位长度private static final String AES = "AES";/*** 解密算法*/public static  String decrypt(String decryptStr, String decryptKey) {try {KeyGenerator kgen = KeyGenerator.getInstance(AES);SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");secureRandom.setSeed(decryptKey.getBytes());kgen.init(128, secureRandom);SecretKey secretKey = kgen.generateKey();Cipher cipher = Cipher.getInstance(ALGORITHMSTR);cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secretKey.getEncoded(), AES));//采用base64算法进行转码,避免出现中文乱码byte[] encryptBytes = Base64.decodeBase64(decryptStr);byte[] decryptBytes = cipher.doFinal(encryptBytes);return new String(decryptBytes);}catch (Exception e){log.error("decryptNew({} , {})解密异常", decryptStr, decryptKey, e);}return null;}/*** 加密算法*/public static  String encrypt(String encryptStr, String encryptKey) {try {KeyGenerator kgen = KeyGenerator.getInstance(AES);SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");secureRandom.setSeed(encryptKey.getBytes());kgen.init(128,secureRandom);SecretKey secretKey = kgen.generateKey();Cipher cipher = Cipher.getInstance(ALGORITHMSTR);cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(secretKey.getEncoded(), AES));byte[] b = cipher.doFinal(encryptStr.getBytes("utf-8"));//采用base64算法进行转码,避免出现中文乱码return Base64.encodeBase64String(b);}catch (Exception e){log.error("encryptNew({} , {})加密异常", encryptStr, encryptKey, e);}return null;}public static void main (String[] args) throws Exception{String content = "今天是2024年1月6日";String encrypt1 = encrypt(content, KEY);System.out.println("加密后:" + encrypt1);String decrypt1 = decrypt(encrypt1, KEY);System.out.println("解密后:" + decrypt1);}
}

结语

本文通过对API安全问题进行粗浅探讨,并从常用的数据加密措施入手,提供相关操作规范和指导,希望各位盆友有所收获。如需进一步了解,可留言,欢迎大家订阅与指正!

2024首篇博文,正式发布喽!!!


历史回顾

  • 微服务实战系列之Dubbo(下)
  • 微服务实战系列之Dubbo(上)
  • 微服务实战系列之ZooKeeper(实践篇)
  • 微服务实战系列之ZooKeeper(下)
  • 微服务实战系列之ZooKeeper(中)
  • 微服务实战系列之ZooKeeper(上)
  • 微服务实战系列之MQ
  • 微服务实战系列之通信
  • 微服务实战系列之J2Cache
  • 微服务实战系列之Cache(技巧篇)
  • 微服务实战系列之MemCache
  • 微服务实战系列之EhCache
  • 微服务实战系列之Redis
  • 微服务实战系列之Cache
  • 微服务实战系列之Nginx(技巧篇)
  • 微服务实战系列之Nginx
  • 微服务实战系列之Feign
  • 微服务实战系列之Sentinel
  • 微服务实战系列之Token
  • 微服务实战系列之Nacos
  • 微服务实战系列之Gateway
  • 微服务实战系列之加密RSA
  • 微服务实战系列之签名Sign

在这里插入图片描述

相关文章:

微服务实战系列之API加密

前言 随着一阵阵凛冽寒风的呼啸&#xff0c;新的年轮不知不觉滚滚而来。故事随着2023的远去&#xff0c;尘封于案底&#xff1b;希望迎着新年&#xff0c;绽放于枝头。在2024新岁启航&#xff0c;扬帆破浪之时&#xff0c;让烦恼抛洒于九霄&#xff0c;让生机蓬勃于朝朝暮暮。 …...

android apk文件的签名问题

android的APK文件实际上是一个jar文件。jar的意思是瓶、罐&#xff0c;那就意味着jar文件是一个用来存放android应用相关文件的容器。事实上&#xff0c;它也确实如此&#xff0c;它只是一个带或不带压缩的zip文件&#xff0c;当你把.apk后缀改成.zip后&#xff0c;就能对此进行…...

ATTCK视角下的信息收集:主机发现

目录 1、利用协议主动探测主机存活 利用ICMP发现主机 利用ARP发现主机 利用NetBIOS协议发现主机 利用TCP/UDP发现主机 利用DNS协议发现主机 利用PRC协议发现主机程序 2、被动主机存活检测 利用Browser主机探测存活主机 利用ip段探测主机存活 利用net命令探测主机存活…...

Redis 主从、哨兵和分片集群简单介绍

Redis 主从集群架构 单节点 redis 并发能力有上限&#xff0c;要进一步提高 redis 并发能力&#xff0c;就要搭建主从集群&#xff0c;实现读写分离 主从同步原理 Replicaition id&#xff1a;每台 master 机器都一个 repl_id&#xff0c;是数据集的表示&#xff0c;若 salv…...

群晖NAS+DMS7.0以上版本+无docker机型安装zerotier

测试机型&#xff1a;群晖synology 218play / DSM版本为7.2.1 因218play无法安装docker&#xff0c;且NAS系统已升级为7.0以上版本&#xff0c;按zerotier官网说法无法安装zerotier, 不过还是可以通过ssh终端和命令方式安装zerotier。 1、在DSM新建文件夹 用于存放zerotier脚…...

Pinia持久化存储插件 pinia-plugin-persist

1、pinia-plugin-persist 作用 pinia-plugin-persist是一个Pinia持久化存储插件&#xff0c;用于将Pinia状态存储到本地持久化存储中&#xff0c;例如localStorage或sessionStorage。 2、安装和使用pinia-plugin-persist 有时候需要把pinia中的数据持久化存储&#xff08;存到…...

链家JAVA笔试题

单选题 1、在Java中下列关于自动类型转换说法正确的是&#xff08; &#xff09;。 A. 基本数据类型和String相加结果一定是字符串型 B. char类型和int类型相加结果一定是字符 C. double类型可以自动转换成int D. char int double “ ”结果一定是double 参考答案&am…...

当试图回复传入消息时,消息应用程序会闪烁

问题描述&#xff1a; Actual Results: Unable to reply for incoming message as Messaging app flickers and closes. Expected Results: User should be able to send reply for incoming messages. Reproduction Steps: Stay in home screen. Receive an incoming mes…...

Hubery-个人项目经历记录

研究生期间很有幸的进入到了崔老师的组&#xff0c;从此也就进入到了分析人体生理信号的领域&#xff0c;充满挑战的同时也充满了乐趣。借着CSDN整理一下近几年来参与的项目&#xff0c;这里蕴含着我各种美好的回忆&#xff0c;也作为一个展示自己的平台吧。博客中很多结果只给…...

Ubuntu18.04 安装 qt 5.15.2

一.安装qt 1.下载 在线安装包 使用国内镜像源在线安装QT(2023.3.25更新)_qt国内镜像-CSDN博客 2.安装 &#xff08;1&#xff09;QT库安装&#xff1a; 注意&#xff1a;我安装时 勾选 Qt Design studio 会导致报错&#xff0c;直接不勾选。 注意&#xff1a;Qtcreator 无…...

【Linux Shell】6. echo 命令

文章目录 【 1. 显示普通字符串 】【 2. 显示转义字符 】【 3. 显示变量 】【 4. 显示换行 】【 5. 显示不换行 】【 6. 显示命令执行结果 】 Shell 的 echo 指令用于字符串的输出。命令格式&#xff1a; echo string【 1. 显示普通字符串 】 #!/bin/bashecho "It is a …...

Dell 机架式服务器 - 高级定制服务

Dell 机架式服务器 - 高级定制服务 1. Dell Technologies2. 机架式服务器 - 高级定制服务2.1. Servers & Storage (服务器及存储) -> Servers2.2. Rack Servers (机架式服务器)2.3. Shop2.4. PowerEdge Rack Servers (PowerEdge 机架式服务器)2.5. PowerEdge R760 Rack …...

C++ 中关键字 Static

1、什么是static? static 是C中很常用的修饰符&#xff0c;它被用来控制变量的存储方式和可见性。由关键字static修饰类中成员&#xff0c;成为类的静态成员。类的静态成员为其所有对象共享&#xff0c;不管有多少对象&#xff0c;静态成员只有一份存于公用内存中。静态…...

系统学习Python——警告信息的控制模块warnings:警告过滤器-[重写默认的过滤器]

分类目录&#xff1a;《系统学习Python》总目录 Python应用程序的开发人员可能希望在默认情况下向用户隐藏所有Python级别的警告&#xff0c;而只在运行测试或其他调试时显示这些警告。用于向解释器传递过滤器配置的sys.warningoptions属性可以作为一个标记&#xff0c;表示是否…...

C++力扣题目-- 二叉树层序遍历

102.二叉树的层序遍历(opens new window)107.二叉树的层次遍历II(opens new window)199.二叉树的右视图(opens new window)637.二叉树的层平均值(opens new window)429.N叉树的层序遍历(opens new window)515.在每个树行中找最大值(opens new window)116.填充每个节点的下一个右…...

前端实现回车键触发搜索

前端实现回车键触发搜索 前言实现方法1. html里可以用 form 来实现2. 非form中的input 前言 搜索框是个常见的功能&#xff0c;除了用现有的ui组件库&#xff0c;有的时候必须要自己封装&#xff0c;所以涉及到点击按钮搜索和回车搜索都要实现 实现方法 1. html里可以用 for…...

k8s yaml文件pod的生命周期

Pod是k8s中最小限额资源管理组件&#xff0c;也是最小化运行容器化的应用的资源管理对象。 Pod是一个抽象的概念&#xff0c;可以理解为一个或者多个容器化应用的集合。 在一个pod当中运行一个容器是最常用的方式。 在一个pod当中同时运行多个容器&#xff0c;在一个pod当中…...

MPEG4Extractor

1、readMetaData 必须要找到 Moov box&#xff0c;找到 Mdat box或者 Moof box&#xff0c;并且创建了 ItemTable 大端 box 分为 box header 和 box content&#xff1a; box header由8个字节组成&#xff0c;前面四个字节表示这个box 的大小&#xff08;包含这个头的8字节&a…...

我在工作一年时怎么都看不懂的编程写法。今天手把手教给你

作为一名程序员&#xff0c;你一定遇到或亲自写过这样的代码。有人将它形象的形容为shi山&#xff0c;或者被戏称为“面向保就业编程”。 以下面这个代码为例&#xff0c;其中的问题也显而易见&#xff0c;当越来越多的条件判断时&#xff0c;代码会变得非常臃肿&#xff0c;难…...

ThinkPHP5多小区物业管理系统源码(支持多小区)

基于 ThinkPHP5 Bootstrap 倾力打造的多小区物业 管理系统源码&#xff0c;操作简单&#xff0c;功能完善&#xff0c;用户体验良好 开发环境PHP7mysql 安装步骤: 1.新建数据库db_estate,还原数据db_estate.sql 2.修改配置文件&#xff1a;application/database.php 3.运…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

第八部分:阶段项目 6:构建 React 前端应用

现在&#xff0c;是时候将你学到的 React 基础知识付诸实践&#xff0c;构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段&#xff0c;你可以先使用模拟数据&#xff0c;或者如果你的后端 API&#xff08;阶段项目 5&#xff09;已经搭建好&#xff0c;可以直接连…...