我正在用Genexus制作的Web登录脚本中使用Jmeter和Blazemeter。 我遇到的问题在POST中。
每当我尝试进行POST http请愿时,Jmeter都会抛出下一件事:
如您所见,在响应正文中,我有一个440 http错误代码。这是登录超时,表示客户端会话已过期,必须再次登录。我曾经有一个403错误代码,但现在,经过一些安排,我有了440。对于如何解决这个问题,您有任何建议吗?
答案 0 :(得分:1)
任何HTTP Status 4xx是客户端错误,以表示您发送的请求不正确。
如果自定义440 http status code表示“会话已过期”,我的期望是您的请求参数或headers
中有记录的硬编码会话ID。一旦找到它,您应该仔细检查以前的响应并查找似乎是会话ID的内容-extract it using a suitable JMeter's Post-Processor,然后用适当的JMeter变量替换硬编码的会话ID。该过程称为 correlation
答案 1 :(得分:1)
首先,我不是 Genexus 的专家。我所有的发现都是从黑匣子的角度来看的。
我发现 Genexus 至少需要两件事才能在 Web 应用程序上进行身份验证(我只测试了 Java 和 .Net 生成的应用程序)。
GXState
参数。这个参数是在 post 请求中发送的,根据我的理解,它是“同步器令牌模式”,请参阅有关 Cross-site request forgery 的更多信息。我们需要在每次发布请求时发送此参数。
gxajaxEvt
参数。这是 Genexus Apps 特有的。在 documentation 中提到此参数在 URL 中加密发送,并且此行为由“Javascript debug mode property”管理:
# Javascript Debug Mode: Yes
http://{server}:{port}/{webappname}/servlet/com.{kbname}.{objectname}?gxfullajaxEvt,gx-no-cache=1442811265833
# Javascript Debug Mode: No (default value)
http://{server}:{port}/{webappname}/servlet/com.{kbname}.{objectname}?64df96a2d9b8480aed416e470dae529e,gx-no-cache=1442811265833
因此,要获得 GXState
,我们可以使用 Regular Expression Extractor
:
创建的变量名称:GXState
正则表达式:name="GXState" value='(.*?)'
模板:$1$
比赛编号:1
默认值:NOT_FOUND
GXState
是一个 JSON 对象,我们可以从中提取 GX_AJAX_KEY
来加密 gxajaxEvt
字符串。请注意,我发现 GX_AJAX_KEY
是在这种情况下用于加密的密钥,但其他一些也可以应用。我们可以使用浏览器 Web 控制台对此进行调试:
gx.sec.encrypt("gxajaxEvt")
我们会看到这样的事情:
"8722e2ea52fd44f599d35d1534485d8e206d507a46070a816ca7fcdbe812b0ad"
我们可以发现,所有客户端加密代码都在 gxgral.js
文件中。 Genexus 使用 Rijndael 算法(AES 的子集),块大小为 128 位。
要在 JMeter 脚本中模拟此客户端行为,我们可以使用“JSR 233 采样器”。获得 Rijndael 结果的一种方法是使用 Bouncy Castle 库。我们需要将此 jar (bouncycastle:bcprov-jdk15to18:1.68) 添加到 JMeter 的 lib 文件夹中才能使用它。
我们的代码脚本将是这样的(Language Groovy 3.0.5/Groovy Scripting Engine 2.0):
import com.jayway.jsonpath.JsonPath
import java.nio.charset.StandardCharsets
import java.util.Arrays
import org.bouncycastle.crypto.BufferedBlockCipher
import org.bouncycastle.crypto.InvalidCipherTextException
import org.bouncycastle.crypto.engines.RijndaelEngine
import org.bouncycastle.crypto.params.KeyParameter
import org.bouncycastle.util.encoders.Hex
import org.apache.jmeter.threads.JMeterContextService
import org.apache.jmeter.threads.JMeterContext
import org.apache.jmeter.threads.JMeterVariables
String gxState = vars.get('GXState')
String gxAjaxKey = JsonPath.read(gxState,'$.GX_AJAX_KEY')
byte[] input = Arrays.copyOf('gxajaxEvt'.getBytes(StandardCharsets.UTF_8), 16)
RijndaelEngine engine = new RijndaelEngine(128)
KeyParameter key = new KeyParameter(Hex.decode(gxAjaxKey))
BufferedBlockCipher cipher = new BufferedBlockCipher(engine)
cipher.init(true, key)
byte[] out = new byte[16]
int length = cipher.processBytes(input, 0, 16, out, 0)
cipher.doFinal(out, length)
String encryptedOutput= Hex.toHexString(out)
log.info 'gx.sec.encrypt("gxajaxEvt")='+encryptedOutput
String gxNoCache = String.valueOf(System.currentTimeMillis())
log.info 'gx-no-cache='+gxNoCache
vars.put('gxajaxEvt', encryptedOutput)
vars.put('gxNoCache', gxNoCache)
脚本是这样工作的:
GXState
变量。GX_AJAX_KEY
属性。gxajaxEvt
上应用 Rijndael 算法,使用 GX_AJAX_KEY
作为键。gx-no-cache
来处理缓存。我们可以找到此示例 JMeter 脚本可用 here。
复杂脚本请参考this guide(需要GXTest)
如果我们在 JMeter (java.util.zip.ZipException: Not in GZIP format
) 中遇到此异常,请也参考此 answer。