fiddler抓包显示客户端加密接口的明文参数
背景:我们在进行客户端抓包时,有的客户端接口的请求参数和响应报文是加密的,不方便查看,有没有办法在抓包时同时显示请求的密文和明文呢?
答案是有的,下面以我现在公司的请求密文为例,如何在fillder中同时显示请求的密文和明文。
先说下公司采用的加密方式AES对称加密:
AES/CBC/PKCS5Padding 是目前最常用的 对称加密方式,由三部分组成:
- AES:加密算法(高级加密标准)
- CBC:加密模式(把数据分块链式加密)
- PKCS5Padding:填充方式(让数据长度满足块要求)
java代码如下:
//解密方式
public static String aesDecrypt(String src, String secretKey, String iv) throws Exception { byte[] encryptedBytes = Base64.decodeBase64(src); byte[] enCodeFormat = secretKey.getBytes(); SecretKeySpec secretAESKey = new SecretKeySpec(enCodeFormat, "AES"); byte[] initParam = iv.getBytes(); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam); cipher.init(Cipher.DECRYPT_MODE, secretAESKey, ivParameterSpec); byte[] result = cipher.doFinal(encryptedBytes); return new String(result, "UTF-8"); } //加密方法 public static String aesEncrypt(String src, String secretKey, String iv) throws Exception { byte[] raw = secretKey.getBytes("UTF-8"); SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec iv1 = new IvParameterSpec(iv.getBytes()); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv1); byte[] encrypted = cipher.doFinal(src.getBytes("UTF-8")); return Base64.encodeBase64String(encrypted); }
操作步骤如下:
1、将上面的解密方式翻译为 Fiddler JScript.NET 版本;
把密钥和AES_Decrypt解密函数和压缩json函数复制到Handlers类中
class Handlers { // ==================== 【改成你自己的 KEY 和 IV】 ==================== private static var AES_KEY = "1234567890123456"; private static var AES_IV = "abcdefghijklmnop"; // ==================== AES 解密函数 ==================== private static function AES_Decrypt(src:String, secretKey:String, iv:String):String { try { var encryptedBytes = Convert.FromBase64String(src.Trim()); var utf8 = new UTF8Encoding(); var keyBytes = utf8.GetBytes(secretKey); var ivBytes = utf8.GetBytes(iv); var aes = new RijndaelManaged(); aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; aes.Key = keyBytes; aes.IV = ivBytes; var decryptor = aes.CreateDecryptor(aes.Key, aes.IV); var ms = new MemoryStream(encryptedBytes); var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read); var sr = new StreamReader(cs, utf8); var plain = sr.ReadToEnd(); sr.Close(); cs.Close(); ms.Close(); return plain; } catch(e) { return "解密失败:" + e.Message; } } // ==================== 工具函数:压缩 JSON 为单行 ==================== private static function CompactJson(str:String):String { return str.Replace("\r","").Replace("\n","").Replace(" ",""); }
2、把上面函数放在customize Rules中,注意需要放在class Handlers类中


3、 在OnBeforeRequest方法中添加如下代码
// 过滤无用请求--解密开始 if (oSession.HTTPMethodIs("CONNECT") || oSession.HostnameIs("msftconnecttest.com")) { oSession["ui-hide"] = "true"; return; } // 判断 source-type 是否 2/3 var sourceType = oSession.oRequest.headers["source-type"]; if (sourceType != "2" && sourceType != "3") return; // 只处理 POST if (!oSession.HTTPMethodIs("POST")) return; // 把明文放到请求头里 try { oSession.utilDecodeRequest(); var reqBody = oSession.GetRequestBodyAsString().Trim(); var reqPlain = AES_Decrypt(reqBody, AES_KEY, AES_IV); // 长度超过 1000 就不放进 header,避免 431 if (reqPlain != null && reqPlain.Length <= 1400) {
oSession.oRequest.headers.Add("X-Request-Plaintext", CompactJson(reqPlain));
} } catch(e) { } // 解密结束
4、在OnBeforeResponse方法中添加如下代码
try { oSession.utilDecodeResponse(); var respBody = oSession.GetResponseBodyAsString().Trim(); var respPlain = AES_Decrypt(respBody, AES_KEY, AES_IV); // 将明文显示在header中 oSession.oResponse.headers.Add("X-Response-Plaintext", CompactJson(respPlain)); } catch(e) {}
最终效果如下:

浙公网安备 33010602011771号