接口越权测试工具类

这篇文章介绍了如何使用Hutool库对CSV文件进行读取,处理请求Bean,发送带有不同Cookie的HTTP请求,并分析响应结果,包括相似度比较和Excel输出功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package cn.silence.service;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.text.csv.CsvWriter;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.silence.model.CommonResp;
import cn.silence.model.RequestBean;
import cn.silence.model.ResponseBean;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.poi.ss.usermodel.CellStyle;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.util.*;
import java.util.List;

/**
 * @author mzq
 * @date 2023/3/29 13:53
 */
@Slf4j
public class Silence {
    /**
     * /输入路径,为文件夹时则遍历该文件夹所有csv文件
     */
    private static final String READ_PATH = "";
    /**
     * 输出路径
     */
    private static final String OUT_PATH = "";
    /**
     * csv文件cookie
     */
    private static final String COOKIE1 = "";
    /**
     * 测试越权的cookie
     */
    private static final String COOKIE2 = "";
    /**
     * 网站请求host 不为该host的请求,会被跳过
     */
    private static final String HOST = "";

    public static void main(String[] args) throws IOException {
        //readPath为文件则 权限测试
        sendPermissionTest();
    }

    private static void sendPermissionTest() throws IOException {
        List<File> files = FileUtil.loopFiles(READ_PATH, f -> f.getName().endsWith(".csv"));
        for (File file : files) {
            log.info("~~~~:{}", file.getName());
            List<RequestBean> requestBeans = readRequestCsv(file.getPath());
            List<ResponseBean> responseBeans = checkProcess(requestBeans);
            outResp(FileUtil.mainName(file), responseBeans);
        }
    }

    @NotNull
    private static List<ResponseBean> checkProcess(List<RequestBean> requestBeans) throws IOException {
        List<ResponseBean> responseBeans = new ArrayList<>(requestBeans.size());
        int count = requestBeans.size();
        HashSet<String> pathSet = new HashSet<>();
        for (RequestBean requestBean : requestBeans) {
            System.out.println(requestBean.getPath() + ":" + (count--));

            //是否跳过
            if (isContinue(requestBean) || !pathSet.add(requestBean.getPath())) {
                continue;
            }
            ResponseBean resp = new ResponseBean();

            //原始结果
            String respStr1 = sendRequest(COOKIE1, requestBean);
            resp.setOriginalResult(format(respStr1));
            //异常信息
            resp.setExceptionInformation("-");
            //接口描述
            resp.setInterfaceDescription("-");

            //接口明细
            resp.setInterfaceDetails(requestBean.getUrL());
            //接口类型
            resp.setInterfaceType(requestBean.getMethod());
            //接口路径
            resp.setInterfacePath(requestBean.getPath());

            //替换结果
            String respStr2 = sendRequest(COOKIE2, requestBean);
            resp.setReplaceResult(format(respStr2));

            //相似度
            resp.setSimilarity(similarityRatio(respStr1, respStr2));
            //移除登录态结果
            resp.setRemoveLoginResults(sendRequest(null, requestBean));
            //未授权访问结果
            resp.setUnauthorizedAccessResults("-");
            //重新请求结果
            resp.setReRequestResult(format(sendRequest(COOKIE2, requestBean)));
            responseBeans.add(resp);
        }
        return responseBeans;
    }

    private static String format(String respStr2) {
        //The maximum length of cell contents (text) is 32767 characters
        int maxSize = 32767;
        //StrUtil.replace(respStr1, ",", "-")
        return StrUtil.sub(respStr2, 0, maxSize);
    }

    private static String similarityRatio(String respStr1, String respStr2) {
        if (StrUtil.isBlank(respStr1) || StrUtil.isBlank(respStr2)) {
            return "0.00%";
        }
        Similarity similarity = new Similarity();
        Object str1;
        try {
            str1 = JSON.parseObject(respStr1, CommonResp.class).getData();
        } catch (Exception e) {
            log.error("json parse error,json:{}", respStr1, e);
            return "-";
        }
        Object str2;
        try {
            str2 = JSON.parseObject(respStr2, CommonResp.class).getData();
        } catch (Exception e) {
            log.error("json parse error,json:{}", respStr2, e);
            return "-";
        }
        float simi = 100;
        if (str1 == null || str2 == null) {
            simi = 0;
        } else if (str1 instanceof JSONArray || str2 instanceof JSONArray) {
            if (str1 instanceof JSONArray) {
                if (((JSONArray) str1).size() == 0) {
                    simi = 0;
                }
            }
            if (str2 instanceof JSONArray) {
                if (((JSONArray) str2).size() == 0) {
                    simi = 0;
                }
            }
        }
        if (simi == 100) {
            respStr1 = str1.toString();
            respStr2 = str2.toString();
            int max = 30000;
            if (respStr1.length() > max || respStr2.length() > max) {
                return "数据量过大,未计算";
            }
            simi = similarity.getSimilarityRatio(respStr1, respStr2);
        }
        if (simi == 0) {
            return "0.00%";
        }
        DecimalFormat decimalFormat = new DecimalFormat("##.00%");
        return decimalFormat.format(simi);
    }

    private static String sendRequest(String cookie, RequestBean requestBean) throws IOException {
        OkHttpClient client = new OkHttpClient();
        Response response = client.newCall(getRequestBody(requestBean, cookie)).execute();
        ResponseBody body = response.body();
        if (body == null) {
            return "";
        }
        String contentType = Objects.requireNonNull(body.contentType()).toString();
        if (ContentType.OCTET_STREAM.getValue().equals(contentType)) {
            log.info("响应为文件流!");
            return null;
        }
        return body.string();
    }

    private static void outResp(String fileName, List<ResponseBean> responseBeans) {
        if (CollUtil.isEmpty(responseBeans)) {
            return;
        }
        //csv
        //        File scvFile = new File(outPath, fileName + ".csv");
        //        outCsv(scvFile, responseBeans);

        //excel
        File excelFile = new File(OUT_PATH, fileName + ".xlsx");
        outExcel(excelFile, responseBeans);
    }

    private static void outExcel(File excelFile, List<ResponseBean> responseBeans) {
        ExcelWriter writer = ExcelUtil.getWriter(excelFile);
        //接口路径
        writer.setColumnWidth(5, 40);
        writer.setColumnWidth(6, 10);
        writer.setColumnWidth(7, 15);
        writer.setColumnWidth(8, 18);
        writer.setColumnWidth(9, 15);
        writer.setColumnWidth(10, 60);
        writer.setDefaultRowHeight(40);
        //解决重新请求结果数据超出
        CellStyle wrapStyle = writer.getCellStyle();
        wrapStyle.setWrapText(true);
        writer.setColumnStyleIfHasData(10, 1, wrapStyle);
        writer.write(responseBeans, true);
        writer.close();
    }

    private static void outCsv(File file, List<ResponseBean> responseBeans) {
        try {
            if (file.exists()) {
                if (!file.delete()) {
                    throw new RuntimeException();
                }
            }
            if (!file.createNewFile()) {
                throw new RuntimeException();
            }
            FileOutputStream out = new FileOutputStream(file);
            byte[] uft8bom = {(byte) 0xef, (byte) 0xbb, (byte) 0xbf};
            out.write(uft8bom);
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        CsvWriter writer = CsvUtil.getWriter(file, StandardCharsets.UTF_8, true);
        writer.writeBeans(responseBeans);
        writer.close();
    }


    private static Request getRequestBody(RequestBean requestBean, String cookie) {
        String header = Base64.decodeStr(requestBean.getRequestParam());
        Map<String, String> headers = new HashMap<>();
        String[] split = header.split(StrUtil.CRLF);
        for (String s : split) {
            if (!s.contains(":")) {
                continue;
            }
            if ("Connection: close".equals(s)) {
                break;
            }
            String sign = ":";
            int i = s.indexOf(sign);
            headers.put(StrUtil.trim(StrUtil.sub(s, 0, i)), StrUtil.trim(StrUtil.sub(s, i + sign.length(), s.length())));
        }
        if (StrUtil.isBlank(cookie)) {
            headers.remove("Cookie");
        } else {
            headers.put("Cookie", cookie);
        }
        Request.Builder builder = new Request.Builder()
                .url(requestBean.getUrL())
                .headers(Headers.of(headers));
        if ("GET".equals(requestBean.getMethod())) {
            return builder.build();
        }

        //post
        String param = getRequestParam(header);
        param = param == null ? "" : param;
        builder.post(RequestBody.create(MediaType.parse("application/json; charset=utf-8"), param));
        return builder.build();
    }

    private static String getRequestParam(String requestHeader) {
        String str = "Connection: close";
        int index = requestHeader.indexOf(str);
        if (index == -1) {
            return null;
        }
        String param = StrUtil.sub(requestHeader, index + str.length(), requestHeader.length());
        if (StrUtil.isBlank(param)) {
            return null;
        }
        return StrUtil.trim(param);
    }

    private static boolean isContinue(RequestBean requestBean) {
        String method = "OPTIONS";
        return !HOST.equals(requestBean.getHost()) || method.equals(requestBean.getMethod());
    }

    private static List<RequestBean> readRequestCsv(String path) {
        final CsvReader reader = CsvUtil.getReader();
        return reader.read(ResourceUtil.getUtf8Reader(path), RequestBean.class);
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Silence丶你的名字

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值