JMeter JSR223脚本报错求助:SHA256+AES加密脚本问题
JMeter JSR223脚本错误排查与修正
问题背景
在JMeter登录测试中,需对CSV读取的密码先执行SHA256哈希,再进行AES加密(目标系统采用前端SHA256+AES的安全机制)。运行JSR223 PreProcessor脚本时触发javax.script.ScriptException,错误指向第17行的String.format方法调用,提示找不到对应静态方法。
错误脚本
import java.security.MessageDigest; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; String plaintextPassword = vars.get("PASSWORD"); try { // Step 1: SHA-256 Hashing MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(plaintextPassword.getBytes()); byte[] digest = md.digest(); StringBuilder sha256Hash = new StringBuilder(); for (byte b : digest) { sha256Hash.append(String.format("%02x", b)); // 第17行,报错行 } String _Key = "____"; // 需替换为实际Base64编码的密钥 // Step 2: AES Encryption Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 从Base64编码的密钥生成SecretKeySpec SecretKeySpec secretKey = new SecretKeySpec(Base64.decodeBase64(_Key), "AES"); _Cipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] encryptedBytes = _Cipher.doFinal(sha256Hash.toString().getBytes()); // 将加密后的字节转换为Base64编码字符串 String encryptedPassword = Base64.encodeBase64String(encryptedBytes); vars.put("encryptedPassword", encryptedPassword); } catch (Exception e) { log.error("Error occurred: " + e.getMessage()); throw new RuntimeException(e); }
错误日志
ERROR o.a.j.m.JSR223PreProcessor: Problem in JSR223 script, JSR223 PreProcessor javax.script.ScriptException: Sourced file: inline evaluation of: ``import java.security.MessageDigest; import javax.crypto.Cipher; import javax.cry . . . '' : Error in method invocation: Static method format( java.lang.String, byte ) not found in class'java.lang.String' : at Line: 17 : in file: inline evaluation of: ``import java.security.MessageDigest; import javax.crypto.Cipher; import javax.cry . . . '' : String .format ( "%02x" , b ) in inline evaluation of: ``import java.security.MessageDigest; import javax.crypto.Cipher; import javax.cry . . . '' at line number 17 at bsh.engine.BshScriptEngine.evalSource(BshScriptEngine.java:93) ~[bsh-2.0b6.jar:2.0b6 2016-02-05 05:16:19] at bsh.engine.BshScriptEngine.eval(BshScriptEngine.java:46) ~[bsh-2.0b6.jar:2.0b6 2016-02-05 05:16:19] at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:231) ~[java.scripting:?] at org.apache.jmeter.util.JSR223TestElement.processFileOrScript(JSR223TestElement.java:232) ~[ApacheJMeter_core.jar:5.6.2] at org.apache.jmeter.modifiers.JSR223PreProcessor.process(JSR223PreProcessor.java:45) ~[ApacheJMeter_components.jar:5.6.2] at org.apache.jmeter.threads.JMeterThread.runPreProcessors(JMeterThread.java:983) ~[ApacheJMeter_core.jar:5.6.2] at org.apache.jmeter.threads.JMeterThread.executeSamplePackage(JMeterThread.java:561) ~[ApacheJMeter_core.jar:5.6.2] at org.apache.jmeter.threads.JMeterThread.processSampler(JMeterThread.java:501) ~[ApacheJMeter_core.jar:5.6.2] at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:268) ~[ApacheJMeter_core.jar:5.6.2] at java.lang.Thread.run(Thread.java:1623) [?:?]
问题分析
- String.format参数兼容问题:BeanShell引擎无法识别
String.format("%02x", byte)的方法签名,因为byte是有符号类型,需转换为无符号int(通过b & 0xFF)才能正确格式化。 - AES CBC模式缺失IV:脚本使用
AES/CBC/PKCS5Padding模式,但未指定初始化向量(IV),CBC模式必须依赖IV才能完成加密初始化,否则会触发异常。
修正后的脚本
import java.security.MessageDigest; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.IvParameterSpec; import org.apache.commons.codec.binary.Base64; String plaintextPassword = vars.get("PASSWORD"); // 替换为与目标系统一致的Base64编码密钥和IV String aesKeyBase64 = "你的Base64编码密钥"; String ivBase64 = "你的Base64编码IV"; try { // Step 1: SHA-256哈希(指定UTF-8编码,与前端保持一致) MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(plaintextPassword.getBytes("UTF-8")); byte[] digest = md.digest(); StringBuilder sha256Hash = new StringBuilder(); for (byte b : digest) { // 将byte转换为无符号int,解决BeanShell兼容问题 sha256Hash.append(String.format("%02x", b & 0xFF)); } // Step 2: AES CBC加密 // 解码Base64格式的密钥和IV byte[] keyBytes = Base64.decodeBase64(aesKeyBase64); byte[] ivBytes = Base64.decodeBase64(ivBase64); SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES"); IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec); // 对SHA256哈希结果加密(指定UTF-8编码) byte[] encryptedBytes = cipher.doFinal(sha256Hash.toString().getBytes("UTF-8")); // 加密结果转换为Base64字符串 String encryptedPassword = Base64.encodeBase64String(encryptedBytes); vars.put("encryptedPassword", encryptedPassword); } catch (Exception e) { log.error("加密处理失败: " + e.getMessage(), e); // 打印完整堆栈便于排查 throw new RuntimeException(e); }
额外注意事项
- 脚本引擎选择:优先使用Groovy引擎而非BeanShell,Groovy性能更高且对Java语法支持更完善,可避免此类兼容问题。在JSR223元件的语言下拉框中选择
groovy即可。 - 密钥与IV一致性:必须确保密钥、IV的编码格式(Base64)和值与目标系统前端完全一致,否则加密结果不匹配。
- 字符编码:所有字节转换操作指定
UTF-8编码,避免因默认编码差异导致哈希/加密结果错误。
内容的提问来源于stack exchange,提问作者mrvnrfm
相关产品推荐
相关产品推荐

