gateway拦截数据加解密

分布式gateway 信息统一拦截加密(复制直接用)

1.和前端协商好加密算法,小编这里用的是AES代码如下
public class AesEncryptUtil {
//使用AES-128-CBC加密模式,key需要为16位,key和iv可以相同!
private static final String KEY = ConstantFilter.S_KEY;
private static final String IV = ConstantFilter.IV_PARAMETER;

/**
* 加密方法
*
* @param data 要加密的数据
* @param key 加密key
* @param iv 加密iv
* @return 加密的结果
* @throws Exception
*/
public static String encrypt(String data, String key, String iv) throws Exception {
try {
Cipher cipher = Cipher.getInstance(“AES/CBC/NoPadding”);//"算法/模式/补码方式"NoPadding PkcsPadding
int blockSize = cipher.getBlockSize();
byte[] dataBytes = data.getBytes();
int plaintextLength = dataBytes.length;
if(plaintextLength % blockSize != 0) {
plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
}
byte[] plaintext = new byte[plaintextLength];
System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), “AES”);
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(plaintext);
return new Base64().encodeToString(encrypted);
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}

/**
* 解密方法
*
* @param data 要解密的数据
* @param key 解密key
* @param iv 解密iv
* @return 解密的结果
* @throws Exception
*/
public static String desEncrypt(String data, String key, String iv) throws Exception {
try {
byte[] encrypted1 = new Base64().decode(data);
Cipher cipher = Cipher.getInstance(“AES/CBC/NoPadding”);
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), “AES”);
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original);
return originalString;
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}

/**
* 使用默认的key和iv加密
*
* @param data
* @return
* @throws Exception
*/
public static String encrypt(String data) throws Exception {
return encrypt(data, KEY, IV);
}

/**
* 使用默认的key和iv解密
*
* @param data
* @return
* @throws Exception
*/
public static String desEncrypt(String data) throws Exception {
return desEncrypt(data, KEY, IV);
}

}

2.对所有返回数据进行加密,具体逻辑是这样的:
(一)获取前端传入的请求头,根据请求头内的值日判断接口是否加密
(二)对数据加密,并且释放掉内存否则会内存溢出
(三)正常返回数据
(四)直接贴代码
public class ResFilter implements GlobalFilter, Ordered {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponse originalResponse = exchange.getResponse();
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
//获取前端传入的请求头,如果授权即默认为加密处理
ServerHttpRequest request = exchange.getRequest();
String token = request.getHeaders().getFirst(ConstantFilter.BG_DEBUG_KEY);
if(ConstantFilter.REQ_RES_ENCRYPT.equals(token)) {
log.info(“返回数据加密状态为【加密】,当前时间:” + new Date());
long lStart = System.currentTimeMillis();
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@Override
public Mono writeWith(Publisher<? extends DataBuffer> body) {
if(body instanceof Flux) {
Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;

              return super.writeWith(fluxBody.buffer().map(dataBuffers -> {

                 DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                 DataBuffer join = dataBufferFactory.join(dataBuffers);

                 byte[] content = new byte[join.readableByteCount()];

                 join.read(content);
                 // 释放掉内存
                 DataBufferUtils.release(join);
                 // 返回值得字符串
                 String str = new String(content, Charset.forName("UTF-8"));
                 log.info("返回的源数据》》小程序:" + str);
                 log.info("返回的源数据》》小程序:" + str);
                 // 把下面加密方法改成你自己的
                 //                     String encryptStr = Base64.getEncoder().encodeToString(Encodes.encryptAES1(str));
                 String encryptStr = null;
                 try {
                    encryptStr = AesEncryptUtil.encrypt(str);
                 }
                 catch(Exception e) {
                    e.printStackTrace();
                 }
                 log.info("返回的加密数据秘钥为:" + "[" + encryptStr + "]");
                 log.info("返回的加密数据秘钥为:" + "[" + encryptStr + "]");
                 originalResponse.getHeaders().setContentLength(encryptStr.getBytes().length);

                 return bufferFactory.wrap(encryptStr.getBytes());
              }));

           }
           return super.writeWith(body);
        }
     };
     //         将响应替换为装饰器
     long lUseTime = System.currentTimeMillis() - lStart;
     log.info("返回加密逻辑耗时为:" + lUseTime + ",毫秒");
     return chain.filter(exchange.mutate().response(decoratedResponse).build());
  }
  //      else if(ConstantFilter.REQ_RES_NALMORE.equals(token)) {
  else {
     long lStart = System.currentTimeMillis();
     log.info("返回数据加密状态为【不加密】,当前时间:" + new Date());
     ServerHttpResponseDecorator decoratedResponse1 = new ServerHttpResponseDecorator(originalResponse) {
        @Override
        public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
           if(body instanceof Flux) {
              Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;

              return super.writeWith(fluxBody.buffer().map(dataBuffers -> {

                 DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                 DataBuffer join = dataBufferFactory.join(dataBuffers);

                 byte[] content = new byte[join.readableByteCount()];

                 join.read(content);
                 // 释放掉内存
                 DataBufferUtils.release(join);
                 // 返回值得字符串
                 String str = new String(content, Charset.forName("UTF-8"));
                 log.info(str);
                 // 把下面加密方法改成你自己的
                 String encryptStr = str;
                 originalResponse.getHeaders().setContentLength(encryptStr.getBytes().length);

                 return bufferFactory.wrap(encryptStr.getBytes());
              }));

           }
           return super.writeWith(body);
        }
     };
     //将响应替换为装饰器
     long lUseTime = System.currentTimeMillis() - lStart;
     log.info("返回参数不加密逻辑耗时为:" + lUseTime + ",毫秒");
     return chain.filter(exchange.mutate().response(decoratedResponse1).build());
  }
  //      return null;

}

@Override
public int getOrder() {
return -1;
}
3.对请求数据进行拦截解密,具体逻辑如下:
(一)重新构造request,参考ModifyRequestBodyGatewayFilterFactory
(二)因为约定了终端传参的格式,所以只考虑json的情况,如果是表单传参,请自行增加
具体代如下:
@Component
@Slf4j
public class ReqFilter implements GlobalFilter, Ordered {

private AntPathMatcher antPathMatcher = new AntPathMatcher();

ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers,
CachedBodyOutputMessage outputMessage)
{
return new ServerHttpRequestDecorator(exchange.getRequest()) {
public HttpHeaders getHeaders() {
long contentLength = headers.getContentLength();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.putAll(super.getHeaders());
if(contentLength > 0L) {
httpHeaders.setContentLength(contentLength);
}
else {
httpHeaders.set(“Transfer-Encoding”, “chunked”);
}
return httpHeaders;
}

     public Flux<DataBuffer> getBody() {
        return outputMessage.getBody();
     }
  };

}

private Mono returnMononew(GatewayFilterChain chain, ServerWebExchange exchange) {
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
}));
}

private Mono readBody(ServerWebExchange exchange, GatewayFilterChain chain) {
//重新构造request,参考ModifyRequestBodyGatewayFilterFactory
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
MediaType mediaType = exchange.getRequest().getHeaders().getContentType();
//重点
Mono modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> {
//因为约定了终端传参的格式,所以只考虑json的情况,如果是表单传参,请自行增加
if(MediaType.APPLICATION_JSON.isCompatibleWith(mediaType) ||
MediaType.APPLICATION_JSON_UTF8.isCompatibleWith(mediaType))
{
String newBody = null;
try {
log.info(“小程序》》前端源数据为:” + body);
log.info(“小程序》》前端源数据为:” + body);
// 解密body 此处调用你自己的解密方法
newBody = AesEncryptUtil.desEncrypt(body);
log.info(“前端解密后的数据为:” + “[” + newBody + “]”);
log.info(“前端解密后的数据为:” + “[” + newBody + “]”);
}
catch(Exception e) {
e.getMessage();
}
return Mono.just(newBody);
}
return Mono.empty();
});
BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
HttpHeaders headers = new HttpHeaders();
headers.putAll(exchange.getRequest().getHeaders());
//猜测这个就是之前报400错误的元凶,之前修改了body但是没有重新写content length
headers.remove(“Content-Length”);
//MyCachedBodyOutputMessage 这个类完全就是CachedBodyOutputMessage,只不过CachedBodyOutputMessage不是公共的
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
ServerHttpRequest decorator = this.decorate(exchange, headers, outputMessage);
return returnMononew(chain, exchange.mutate().request(decorator).build());
}));
}

private Mono notDecrypt(ServerWebExchange exchange, GatewayFilterChain chain) {
//重新构造request,参考ModifyRequestBodyGatewayFilterFactory
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
MediaType mediaType = exchange.getRequest().getHeaders().getContentType();
//重点
Mono modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> {
//因为约定了终端传参的格式,所以只考虑json的情况,如果是表单传参,请自行增加
if(MediaType.APPLICATION_JSON.isCompatibleWith(mediaType) ||
MediaType.APPLICATION_JSON_UTF8.isCompatibleWith(mediaType))
{
String newBody = null;
try {
// 解密body 此处调用你自己的解密方法
newBody = body;
}
catch(Exception e) {
e.getMessage();
}
return Mono.just(newBody);
}
return Mono.empty();
});
BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
HttpHeaders headers = new HttpHeaders();
headers.putAll(exchange.getRequest().getHeaders());
//猜测这个就是之前报400错误的元凶,之前修改了body但是没有重新写content length
headers.remove(“Content-Length”);
//MyCachedBodyOutputMessage 这个类完全就是CachedBodyOutputMessage,只不过CachedBodyOutputMessage不是公共的
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
ServerHttpRequest decorator = this.decorate(exchange, headers, outputMessage);
return returnMononew(chain, exchange.mutate().request(decorator).build());
}));
}

@SneakyThrows
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

  ServerHttpRequest request = exchange.getRequest();
  ServerHttpResponse response = exchange.getResponse();
  String path = request.getURI().getPath(); // 当前调用方法的url
  HttpHeaders headers = request.getHeaders();
  log.info("HttpMethod:{},Url:{}", request.getMethod(), request.getURI().getRawPath());
  //  登录跳过网关验证,检查白名单(配置)最好把不拦截路径放入配置文件,此处通过正则
  if(antPathMatcher.match("/**/api/login/auth/**", path)) {
     return readBody(exchange, chain);
  }
  // 处理参数
  MediaType contentType = headers.getContentType();
  long contentLength = headers.getContentLength();
  ServerHttpRequest request1 = exchange.getRequest();
  //目前支持POST
  if(contentLength > 0) {
     long lStart = System.currentTimeMillis();
     if(MediaType.APPLICATION_JSON.equals(contentType) || MediaType.APPLICATION_JSON_UTF8.equals(contentType)) {
        if(ConstantFilter.REQ_RES_ENCRYPT.equals(request1.getHeaders().getFirst(ConstantFilter.BG_DEBUG_KEY))) {
           log.info("入参加密状态为【解密】,当前时间:" + new Date());
           return readBody(exchange, chain);
        }
        //            else if(ConstantFilter.REQ_RES_NALMORE.equals(
        //               request1.getHeaders().getFirst(ConstantFilter.BG_DEBUG_KEY)))
        //            {
        else {
           log.info("入参加密状态为【不解密】,当前时间:" + new Date());
           return notDecrypt(exchange, chain);
        }
     }
     long lUseTime = System.currentTimeMillis() - lStart;
     log.info("入参加密逻辑耗时:" + lUseTime + ",毫秒");
  }
  return chain.filter(exchange);

}

@Override
public int getOrder() {
return 0;
}

}

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
网关加解密攻击是指攻击者利用漏洞或弱点,对网络中的网关设备进行攻击,以获取加密数据或篡改数据的过程。这种攻击可能会导致敏感信息泄露、数据篡改、身份伪造等安全问题。 攻击者可以利用多种方式进行网关加解密攻击,包括但不限于以下几种: 1. 中间人攻击:攻击者通过欺骗网关和终端设备之间的通信,将自己置于通信路径中,并以两者之间的代理身份进行通信。这使得攻击者能够获取加密通信中的数据,或者篡改数据。 2. 重放攻击:攻击者截获网络中的加密数据包,并将其重新发送到目标网关。这可能导致网关误认为数据包是合法的,并解密或执行相应的操作。攻击者可以利用这种方式重复发送已知数据包,从而实现攻击目的。 3. 密钥破解:攻击者可能尝试通过暴力破解或其他方式获取网关使用的加密密钥。一旦密钥被破解,攻击者就可以解密和篡改经过网关的加密数据。 为了防止网关加解密攻击,可以采取以下措施: 1. 强化网络安全:定期对网关设备进行漏洞扫描和安全评估,及时修补漏洞和弱点,确保设备的安全性。 2. 密钥管理:使用强密码和密钥管理机制,定期更换密钥,并确保密钥的安全存储和传输。 3. 加密协议选择:选择安全可靠的加密协议,如TLS/SSL等,并配置正确的加密参数,以提高通信的安全性。 4. 监测和检测:部署入侵检测系统(IDS)和入侵防御系统(IPS),实时监测网关设备的网络流量和行为,及时检测并阻止潜在的攻击。 5. 用户教育:加强用户的安全意识和培训,防止社会工程学攻击和钓鱼攻击,减少人为因素对网关安全的影响。 请注意,以上措施只是一些基本建议,并不能完全保证网关的安全。实际应用中,还需要根据具体情况制定更为细化和全面的安全策略。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值