gateway接口参数加解密

上篇介绍了多种加解密的使用java加密使用
本篇主要介绍在gateway网关中使用对参数解密和返回数据进行加密的操作

原理

下面使用的是AES加密 SHA1withRSA加签

1-用户使用拿到的AES秘钥和RSA私钥。对数据进行加密和加签
2-进行验签和时间的检验
3-将解密的数据返回到具体的调用方(通过特定的filter具体业务方是无感知加解密的)
4-将业务方数据加密返回给调用方

参数校验

@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE + 10)
@Component
public class SignatureValidationGatewayFilterFactory extends AbstractGatewayFilterFactory {

    private final EtrGatewayProperties etrGatewayProperties;

    @Autowired
    public SignatureValidationGatewayFilterFactory(EtrGatewayProperties etrGatewayProperties) {
        this.etrGatewayProperties = etrGatewayProperties;
    }

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            if (HttpMethod.GET.matches(exchange.getRequest().getMethodValue())
                    || HttpMethod.POST.matches(exchange.getRequest().getMethodValue())) {
                ModifyRequestBodyGatewayFilterFactory.Config modifyRequestConfig = new ModifyRequestBodyGatewayFilterFactory.Config()
                        .setContentType(ContentType.APPLICATION_JSON.getMimeType())
                        .setRewriteFunction(String.class, String.class, (exchange1, originalRequestBody) -> {
                            try {
                                JSONObject jsonObject = JSONUtil.parseObj(originalRequestBody);
                                String appId = jsonObject.getStr(SignatureConstants.SIGN_APPID);
                                String sign = jsonObject.getStr(SignatureConstants.SIGN_KEY);
                                String signType = jsonObject.getStr(SignatureConstants.SIGN_TYPE);
                                String timeStamp = jsonObject.getStr(SignatureConstants.SIGN_TIME_STAMP);
                                EtrGatewayProperties.SinatureConfig first = etrGatewayProperties.getSignatures().stream()
                                        .filter(appConfig -> appConfig.getAppId().equalsIgnoreCase(appId))
                                        .findFirst().orElse(null);
                                if (Objects.isNull(first)) {
                                    log.error("appId:{}不合法", appId);
                                    return Mono.error(BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR));
                                }
                                if (StrUtil.isBlank(sign) || StrUtil.isBlank(signType) || !StrUtil.isNumeric(timeStamp)) {
                                    log.error("参数不合法:sign:{},signType:{},timestamp:{}", sign, signType, timeStamp);
                                    return Mono.error(BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR));
                                }

                                // 验证时间戳
                                if (!validateTimestamp(timeStamp, first)) {
                                    log.warn("Invalid timestamp for appId: {}", appId);
                                    return Mono.error(BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR));
                                }

                                // 验证签名
                                if (!validateSignature(jsonObject, appId, signType, sign, first)) {
                                    log.warn("Signature verification failed for appId: {}", appId);
                                    return Mono.error(BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR));
                                }

                                String dataStr = decryptData(jsonObject.getStr(SignatureConstants.SIGN_DATA), first.getAesKey());

                                if (StringUtils.isBlank(dataStr)) {
                                    return Mono.error(BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR));
                                }

                                exchange1.getRequest().mutate().header(SignatureConstants.SIGN_APPID, appId);
                                return Mono.just(dataStr);
                            } catch (Exception e) {
                                return Mono.error(e);
                            }
                        });

                return new ModifyRequestBodyGatewayFilterFactory()
                        .apply(modifyRequestConfig)
                        .filter(exchange, chain)
                        .onErrorResume(e -> handleFilterError(exchange, e));
            }

            return chain.filter(exchange);
        };
    }

    private boolean validateTimestamp(String timeStamp, EtrGatewayProperties.SinatureConfig appConfig) {
        Integer timestampExpire = Optional.ofNullable(appConfig.getTimeStampExpire()).orElse(300);
        DateTime time = DateUtil.parse(timeStamp, DateUtil.newSimpleFormat("yyyyMMddHHmmss"));
        long between = DateUtil.between(time, new Date(), DateUnit.SECOND);
        return Math.abs(between) <= timestampExpire;
    }

    private boolean validateSignature(JSONObject jsonObject, String appId, String signType, String sign, EtrGatewayProperties.SinatureConfig appConfig) {
        String publicKey = appConfig.getPublicKey();
        SignStrategy signStrategy = new DefaultSignStrategy();
        try {
            return signStrategy.verifyPost(jsonObject.getStr(SignatureConstants.SIGN_DATA), publicKey,
                    CipherType.valueOf(signType.toUpperCase()), sign);
        } catch (Exception e) {
            log.error("Signature verification failed for appId: {}", appId, e);
            return false;
        }
    }

    private String decryptData(String data, String aesKey) {
        AES aes = SecureUtil.aes(aesKey.getBytes());
        return aes.decryptStr(data);
    }

    private Mono<Void> handleFilterError(ServerWebExchange exchange, Throwable e) {
        if (e instanceof BizException) {
            log.error("Filter error: {}", e.getMessage());
            return signatureError(exchange);
        }
        return Mono.error(e);
    }

    private Mono<Void> signatureError(ServerWebExchange exchange) {
        log.warn("Signature error: {}", exchange.getRequest().getURI().getPath());
        ApiResult<Object> result = ApiResult.fail(GatewayErrorCodeEnum.SIGNATURE_ERROR);
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        DataBuffer buffer = response.bufferFactory().wrap(JSONUtil.toJsonStr(result).getBytes());
        return response.writeWith(Mono.just(buffer)).then(Mono.defer(response::setComplete));
    }
}

返回参数加密

@Order(Ordered.HIGHEST_PRECEDENCE + 20)
@Component
public class SignatureResGatewayFilterFactory extends ModifyResponseBodyGatewayFilterFactory {

    private final EtrGatewayProperties etrGatewayProperties;

    public SignatureResGatewayFilterFactory(ServerCodecConfigurer codecConfigurer, Set<MessageBodyDecoder> bodyDecoders,
                                            Set<MessageBodyEncoder> bodyEncoders, EtrGatewayProperties etrGatewayProperties) {
        super(codecConfigurer.getReaders(), bodyDecoders, bodyEncoders);
        this.etrGatewayProperties = etrGatewayProperties;
    }

    @Override
    public GatewayFilter apply(Config config) {
        config.setRewriteFunction(String.class, String.class, (serverWebExchange, s) -> {
            JSONObject resJson = JSONUtil.parseObj(s);
            Integer code = resJson.getInt("code");
            if (200 == code) {
                String dataStr = resJson.getStr("data");
                if (StrUtil.isNotBlank(dataStr)) {
                    String appId = serverWebExchange.getRequest().getHeaders().getFirst(SignatureConstants.SIGN_APPID);
                    if (StrUtil.isBlank(appId)) {
                        return Mono.error(BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR));
                    }
                    AES aes = SecureUtil.aes(getAesKey(appId).getBytes());
                    resJson.set("data", aes.encryptBase64(dataStr));
                    return Mono.just(resJson.toString());
                }
            }
            return Mono.just(s);

        });
        ModifyResponseGatewayFilter gatewayFilter = new ModifyResponseGatewayFilter(config);
        gatewayFilter.setFactory(this);
        return gatewayFilter;
    }

    private String getAesKey(String appId) {
        EtrGatewayProperties.SinatureConfig first = etrGatewayProperties.getSignatures().stream()
                .filter(appConfig -> appConfig.getAppId().equalsIgnoreCase(appId))
                .findFirst().orElse(null);
        if (Objects.isNull(first)) {
            throw BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR);
        }

        String aesKey = first.getAesKey();
        if (StrUtil.isBlank(aesKey)) {
            throw BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR);
        }
        return aesKey;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值