Springboot請求引數解密

浪天涯&*發表於2024-12-06

新建一個 HttpServletRequestWrapper 實現類,在Filter 中使用該類包裝原request

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.net.URLDecoder;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.test.base.config.SecretConfig;
import com.test.common.constant.CommonConstant;
import com.test.common.exception.IchibanShoException;
import com.test.common.servlet.CommonServletInputStream;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Slf4j
public class DecryptHttpServletRequest extends HttpServletRequestWrapper {
    private byte[] body;
    private static SecretConfig secretConfig;
    private final Map<String, String[]> parameterMap = new HashMap<>();

    public DecryptHttpServletRequest (HttpServletRequest request) {
        super(request);
        if (Objects.isNull(secretConfig)) {
            secretConfig = SpringUtil.getBean(SecretConfig.class);
        }
        if (MapUtil.isNotEmpty(request.getParameterMap())) {
            parameterMap.putAll(request.getParameterMap());
        }
        decryptSecretParam();
        decryptPostBody(request);
    }

    private void decryptSecretParam() {
        String secretParam = getParameter("secretParam");
        MapUtil.removeAny(parameterMap, "secretParam");
        if (StrUtil.isNotBlank(secretParam) && Objects.nonNull(secretConfig)) {
            log.info(">>>>>>>>>>> 解密 secretParam 開始 <<<<<<<<<<<<<<<<<<");
            log.info("原始secretParam: {}", secretParam);
            secretParam = URLDecoder.decode(secretParam, StandardCharsets.UTF_8);
            log.info("URLDecoder後secretParam: {}", secretParam);
            String privateKey = secretConfig.getPrivateKey();
            String publicKey = secretConfig.getPublicKey();
            if (CharSequenceUtil.isNotBlank(privateKey)) {
                RSA rsa = SecureUtil.rsa(privateKey, publicKey);
                rsa.setDecryptBlockSize(CommonConstant.RSA_DECRYPT_BLOCK_SIZE);//hutool RSA解密預設128
                String decryptData = rsa.decryptStr(secretParam, KeyType.PrivateKey);
                log.info("RSA解碼後secretParam: {}", decryptData);
                decryptData = URLDecoder.decode(decryptData, StandardCharsets.UTF_8);
                log.info("URLDecoder後decryptData: {}", decryptData);
                if (CharSequenceUtil.isNotBlank(decryptData)) {
                    decryptData = StrUtil.removePrefix(decryptData, "\"");
                    decryptData = StrUtil.removeSuffix(decryptData, "\"");
                    log.info("去除首尾雙引號後decryptData: {}", decryptData);
                    List<String> params = StrUtil.split(decryptData, "&");
                    for (String param : params) {
                        List<String> paramArr = StrUtil.splitTrim(param, "=");
                        if (CollUtil.isNotEmpty(paramArr) && paramArr.size() == 2) {
                            setParameter(paramArr.get(0), paramArr.get(1));
                        }
                    }
                }
            }
            log.info(">>>>>>>>>>> 解密 secretParam 結束 <<<<<<<<<<<<<<<<<<");
        }
    }

    private void decryptPostBody(HttpServletRequest request) {
        try {
            InputStream inputStream = request.getInputStream();
            String bodyStr = IoUtil.read(new InputStreamReader(inputStream));
            if (JSONUtil.isTypeJSON(bodyStr)) {
                JSONObject jsonObject = JSONUtil.parseObj(bodyStr);
                if (jsonObject.containsKey("secretData")) {
                    bodyStr = jsonObject.getStr("secretData");
                }
            }
            if (!JSONUtil.isTypeJSON(bodyStr) && CharSequenceUtil.isNotBlank(bodyStr) && Objects.nonNull(secretConfig)) {
                log.info(">>>>>>>>>>> 解密 secretData 開始 <<<<<<<<<<<<<<<<<<");
                log.info("原始secretData: {}", bodyStr);
                String privateKey = secretConfig.getPrivateKey();
                String publicKey = secretConfig.getPublicKey();
                if (CharSequenceUtil.isNotBlank(privateKey)) {
                    RSA rsa = SecureUtil.rsa(privateKey, publicKey);
                    rsa.setDecryptBlockSize(CommonConstant.RSA_DECRYPT_BLOCK_SIZE);
                    String decryptData = rsa.decryptStr(bodyStr, KeyType.PrivateKey);
                    log.info("RSA解碼後secretData: {}", decryptData);
                    decryptData = URLDecoder.decode(decryptData, StandardCharsets.UTF_8);
                    log.info("URLDecoder後secretData: {}", decryptData);
                    if (CharSequenceUtil.isNotBlank(decryptData)) {
                        body = CharSequenceUtil.bytes(decryptData);
                    } else {
                        throw new IchibanShoException("無效的請求引數");
                    }
                } else {
                    body = CharSequenceUtil.bytes(bodyStr);
                }
                log.info(">>>>>>>>>>> 解密 secretData 結束 <<<<<<<<<<<<<<<<<<");
            } else {
                body = CharSequenceUtil.bytes(bodyStr);
            }
        } catch (Exception e) {
            log.error("解密失敗", e);
        }
    }

    public void setParameter(String name, String value) {
        parameterMap.put(name, new String[] { value });
    }

    @Override
    public String getParameter(String name) {
        String[] values = parameterMap.get(name);
        if (ArrayUtil.isNotEmpty(values)) {
            return values[0];
        }
        return StrUtil.EMPTY;
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        return parameterMap;
    }

    @Override
    public Enumeration<String> getParameterNames() {
        Vector<String> parameterNames = new Vector<>(parameterMap.keySet());
        return parameterNames.elements();
    }

    @Override
    public String[] getParameterValues(String name) {
        return parameterMap.get(name);
    }

    @Override
    public ServletRequest getRequest() {
        return super.getRequest();
    }

    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(body)));
    }

    @Override
    public ServletInputStream getInputStream() {
        return new CommonServletInputStream(new ByteArrayInputStream(body));
    }
}

  

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;

public class CommonServletInputStream extends ServletInputStream {
    private final ByteArrayInputStream inputStream;

    public CommonServletInputStream(ByteArrayInputStream inputStream) {
        this.inputStream = inputStream;
    }

    @Override
    public boolean isFinished() {
        return inputStream.available() == 0;
    }

    @Override
    public boolean isReady() {
        return true;
    }

    @Override
    public void setReadListener(ReadListener readListener) {

    }

    @Override
    public int read() {
        return inputStream.read();
    }

    @Override
    public void close() throws IOException {
        inputStream.close();
    }
}

  在filter中:filterChain.doFilter(new DecryptHttpServletRequest(request), response);

相關文章