前言
公司有個網站系統,用戶名是明文,密碼是加密的,所以搞了好久才登錄進去,因此記錄下艱辛過程。
Part 1 了解加密算法
找研發同事去了解這個是怎樣一個加密過程,最后得到的結論是:后端會生成一個16位的隨機數,由前端來加密,而前端是用AES的CBC模式加密的。因為前端是用JS實現的,而jmeter是用java,所以不能直接貼前端代碼。
Part 2 開始百度之旅
各種百度,最后參照2篇博文,然后copy了代碼過來優化了下,輸出的密碼密文如下:
參照的博客地址:
1.https://www.cnblogs.com/artoftest/p/7277996.html
2.https://blog.csdn.net/qq_39820860/article/details/95963968
Part 3 卡住了,不過解決了
以為這么容易就結束了嗎?不,還有第3part呢,在加密算法搞定后,接口一直提示認證失敗,起初以為是網上找的加密算法跟公司用的不一樣,但是找研發看了,說是一樣的,最后終於在研發同事的提醒下,找到原因了,原來是登錄的接口請求時要用到前面那個接口生成的cookie,唉,真心不容易。上面只是簡單貼了下資料,下面具體說下運用吧。
Part 4 完整實例演示
1、添加http請求 獲取登錄的key接口(GET):http://../login/getSecretKey
Response Body :{"msg":"success","code":"0","info":{"key":"a2c893cfa0684897"}}
Response headers:
HTTP/1.1 200 OK
Server: openresty/1.11.2.5
Date: Fri, 27 Nov 2020 13:18:12 GMT
Content-Type: text/plain;charset=UTF-8
Content-Length: 62
Connection: keep-alive
Set-Cookie: PHPSESSID=a4b06bc0-9974-4b22-aa25-efcd4e969d4e; Path=/; HttpOnly; SameSite=lax
X-Application-Context: FspService:test:8001
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization
正則表達式提取:
key--從Response Body提取-------------在登錄接口會引用到
PHPSESSID--從Response headers提取---------------在信息頭管理器會引用到
2、添加BeanShell 取樣器 對前面接口提取的key進行AES加密,完整代碼如下:
//導入需要的加密包 import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; //加密 public static String encrypt(String data, String key) { String ivString = key; //偏移量 byte[] iv = ivString.getBytes(); try { Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); int blockSize = cipher.getBlockSize(); byte[] dataBytes = data.getBytes(); int length = dataBytes.length; //計算需填充長度 if (length % blockSize != 0) { length = length + (blockSize - (length % blockSize)); } byte[] plaintext = new byte[length]; //填充 System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length); SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES"); //設置偏移量參數 IvParameterSpec ivSpec = new IvParameterSpec(iv); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); byte[] encryped = cipher.doFinal(plaintext); return Base64.encodeBase64String(encryped); } catch (Exception e) { e.printStackTrace(); return null; } } //解密 public static String desEncrypt(String data, String key) { String ivString = key; byte[] iv = ivString.getBytes(); try { byte[] encryp = Base64.decodeBase64(data); Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES"); IvParameterSpec ivSpec = new IvParameterSpec(iv); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); byte[] original = cipher.doFinal(encryp); return new String(original); } catch (Exception e) { e.printStackTrace(); } return null; } String data = "abcd1234";//這是明文密碼 String key = "${key}";//key引用了變量,即前面接口提取出來的key String encrypt = encrypt(data,key); String desencrypt = desEncrypt(encrypt, key); vars.put("enString",encrypt);//把加密的密碼設置為變量enString,供后面登錄接口使用 System.out.println("加密后:"+encrypt); System.out.println("解密后:"+desencrypt); log.info("加密后:"+encrypt);//打印日志到控制台 log.info("解密后:"+desencrypt);
3、添加http請求 登錄接口(POST):http://../login/login
消息體數據:{"password":"${enString}","userName":"用戶名","isMobile":false}
4、HTTP信息頭管理器
Cookie引用第1個接口生成的PHPSESSID值變量,前面就是被這個變量阻塞了好久
5、以上就完結啦,下面展示下線程組框架和debug