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);
}
}
接口越权测试工具类
最新推荐文章于 2024-08-12 08:58:04 发布