简述
本文涉及代码已开源
本文网关gateway,微服务,vue已开源到gitee
杉极简 / gateway网关阶段学习
https://gitee.com/dong-puen/gateway-stages
Fir Cloud 完整项目
该内容完整项目如下
Fir Cloud v1.0.0
https://gitee.com/dong-puen/fir-cloud
https://github.com/firLucky/fir-cloud
完整性
避免数据在传输、存储或处理过程中未被未经授权的第三方修改或损坏。
必要性:
- 防止数据篡改:确保数据在传输过程中不被恶意篡改,对于保护敏感信息和维护数据准确性至关重要。
- 维护信任:数据和系统的完整性是建立和维护用户信任的基础。用户需要相信他们的数据是安全的,并且不会被未经授权的第三方访问或更改。
- 防止恶意攻击:网络攻击者可能会尝试破坏系统的完整性,以达到各种恶意目的,如窃取数据、发起勒索软件攻击或进行其他形式的网络犯罪。
- 保障业务连续性:系统的完整性对于确保业务连续性和最小化潜在的业务中断至关重要。
作用:
- 数据验证:通过确保数据的完整性,网关可以验证数据在传输过程中未被更改,从而保护数据的真实性和可靠性。
- 安全审计:完整性检查可以作为安全审计的一部分,帮助检测和记录任何未经授权的尝试更改数据或系统的行为。
- 事故响应:在发生安全事件时,完整性保护措施可以帮助快速识别和隔离问题,从而减少损害并加速恢复过程。
- 增强防御:通过实施完整性保护,网关可以作为额外的安全层,增强整个系统的防御能力。
整体效果
前端如果不加特定参数将会被后端拦截。
前端经过处理之后,增加一个请求头参数C。
即可通过后端的校验处理。
后端
增加完整性检验开关配置
# 完整性校验
reqIntegrity: true
GlobalConfig增加
/**
* 完整性校验
*/
private boolean reqIntegrity;
完整性检验-请求拦截器
package com.fir.gateway.filter.request;
import com.alibaba.fastjson.JSONObject;
import com.fir.gateway.config.GlobalConfig;
import com.fir.gateway.config.exception.CustomException;
import com.fir.gateway.config.result.AjaxResult;
import com.fir.gateway.config.result.AjaxStatus;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
/**
* 完整性检验-请求拦截器
*
* @author fir
*/
@Slf4j
@Component
public class ReqIntegrityFilter implements GlobalFilter, Ordered {
/**
* 网关参数配置
*/
@Resource
private GlobalConfig globalConfig;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("完整性校验:start");
boolean reqIntegrity = globalConfig.isReqIntegrity();
if(reqIntegrity) {
ServerHttpRequest request = exchange.getRequest();
// 获取请求的相关信息
HttpMethod method = request.getMethod();
String path = request.getPath().toString();
// 白名单路由判断
List<String> whiteUrls = globalConfig.getWhiteUrls();
if(whiteUrls.contains(path)){
log.info("完整性校验:true,白名单");
return chain.filter(exchange);
}
MultiValueMap<String, String> query = request.getQueryParams();
String queryJson = JSONObject.toJSONString(query);
// request.getQueryParams() 获取到的参数使得前后端完整性参数不一致,故暂时使用去除中括号[]的方式使得前后端统一
queryJson = queryJson.replaceAll("\\[|\\]", "");
queryJson = queryJson.replaceAll("\\\"", "");
// 计算请求的完整性校验值
String calculatedChecksum;
if (method != null) {
calculatedChecksum = calculateChecksum(method, path, queryJson);
} else {
log.error("完整性校验失败:请求类型获取失败,请求类型为空");
throw new CustomException(AjaxStatus.INTEGRITY_VERIFY_FAILED);
}
// 获取请求中携带的校验值
String providedChecksum = request.getHeaders().getFirst("c");
// 比较校验值
if (calculatedChecksum != null && calculatedChecksum.equals(providedChecksum)) {
log.info("完整性校验:true");
// 校验通过,继续处理请求
return chain.filter(exchange);
} else {
log.info("完整性校验:false");
// 校验失败,拒绝请求
// 如果不合法,则返回错误响应
ServerHttpResponse response = exchange.getResponse();
// 自定义返回体描述
AjaxResult error = AjaxResult.error(AjaxStatus.INTEGRITY_VERIFY_FAILED);
String resData = JSONObject.toJSONString(error);
byte[] responseBody = resData.getBytes(StandardCharsets.UTF_8);
response.getHeaders().setContentLength(responseBody.length);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
return response.writeWith(Mono.just(response.bufferFactory().wrap(responseBody)));
}
}else {
log.info("完整性校验:true,验证已关闭");
}
return chain.filter(exchange);
}
@SneakyThrows
private String calculateChecksum(HttpMethod method, String path, String query) {
// TODO: 根据具体需求计算请求的完整性校验值,可以使用哈希算法或消息认证码
// 示例:使用HMAC-SHA256计算校验值
String data = method.toString() + path + query;
// byte[] secretKeyBytes = SECRET_KEY.getBytes(StandardCharsets.UTF_8);
// SecretKeySpec keySpec = new SecretKeySpec(secretKeyBytes, "HmacSHA256");
// Mac mac = Mac.getInstance("HmacSHA256");
// mac.init(keySpec);
// byte[] checksumBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
// // 将解密结果转为字符串
// return Base64.getEncoder().encodeToString(checksumBytes);
byte[] bytes = data.getBytes();
//Base64 加密
return Base64.getEncoder().encodeToString(bytes);
}
@Override
public int getOrder() {
// 设置过滤器的优先级
return -190;
}
}
前端
增加全局配置
// 完整性
const reqIntegrity = true;
请求拦截器添加完整性
gatewayRequest中增加
// 完整性校验信息
if (reqIntegrity) {
request.headers.c = this.calculateChecksum(request.method, request.url, request.params)
}
完整性签名生成
//************************************完整性start
/**
* 完整性签名生成
*
* @param method 请求类型
* @param path 请求地址
* @param query 请求参数
* @returns {*} 签名密钥
*/
calculateChecksum(method, path, query) {
let param
if (query === null || query === undefined) {
param = "{}"
} else {
param = JSON.stringify(query)
param = param.replace(/\[|\]/g, '');
param = param.replace(/"/g, '');
}
// 将请求的方法、路径和查询参数拼接成一个字符串
let data = `${method.toUpperCase()}${path}${param}`;
return this.gBase(data);
},
//************************************完整性-end