京东质量社区 Jmeter 实现 HTTPS 双向认证方案

taki for 京东 · 2017年03月24日 · 最后由 老马 回复于 2018年08月10日 · 5540 次阅读

目前一般 web 应用都是采用单向认证的,原因很简单,用户数目广泛,且无需做在通讯层做用户身份验证,一般都在应用逻辑层来保证用户的合法登入。
但如果是企业应用对接,情况就不一样,可能会要求对 client(相对而言)做身份验证。这时需要做双向认证


针对单向认证的 Jmeter 其实不用导入证书也可以调用,Jmeter 默认是忽略证书的,双向的我们需要看在 Jmeter 的 System 里面增加 trustStore 秘钥库的设置,我们先看看 SSLManager 类里面的几个常量

private static final String SSL_TRUST_STORE = "javax.net.ssl.trustStore";// 证书库

private static final String KEY_STORE_PASSWORD = "javax.net.ssl.keyStorePassword"; // 密码

public static final String JAVAX_NET_SSL_KEY_STORE = "javax.net.ssl.keyStore"; // 证书库

双向认证在需要客户端证书的同时也需要对客户端认证,所以我们把服务端的证书放在trustStore证书库里面


操作步骤

1.首先在 System.propertis 里面增加javax.net.ssl.trustStore=D:\key\client.truststore

# Truststore properties (trusted certificates)
javax.net.ssl.trustStore=D:\\key\\client.truststore

truststore 也是需要密码的,大家在通过 SSL 管理器导入证书时要输入密码truststore 用的也是这个密码,所以这里面truststore的密码要和keyStore的密码保持一致,因为在 Jmeter 的源代码里面都是调用的一个获取密码,看下源码

private String getPassword() {
        String password = System.getProperty(KEY_STORE_PASSWORD);
        if (null == password) {
            final GuiPackage guiInstance = GuiPackage.getInstance();
            if (guiInstance != null) {
                synchronized (this) { // TODO is sync really needed?
                    this.defaultpw = JOptionPane.showInputDialog(
                            guiInstance.getMainFrame(),
                            JMeterUtils.getResString("ssl_pass_prompt"),  // $NON-NLS-1$
                            JMeterUtils.getResString("ssl_pass_title"),  // $NON-NLS-1$
                            JOptionPane.QUESTION_MESSAGE);
                    System.setProperty(KEY_STORE_PASSWORD, this.defaultpw);
                    password = this.defaultpw;
                }
            } else {
                log.warn("No password provided, and no GUI present so cannot prompt");
            }
        }
        return password;
    }

2.truststore设置完成之后,在通过 SSL 管理器导入证书


3.设置完上面两个就可以正常调用了,


4.那么通过 SSL 管理器导入证书是不保存在你的 JMX 脚本里面的,所以需要手工做一下,这个时候也可以通过 System.property 设置 (javax.net.ssl.keyStore=D:\key\client.p12) 里面设置证书和 trustStore 一样,本着 JAVA 的思想,一次编译多环境执行的概念,修改 System.property 的配置文件并不是很好,所以我们可以采取一下做法

因为 Jmeter 是从系统系统变量里面获取的路径所以我们要 System.property,采取 Beanshell 设置

import org.apache.jmeter.util.SSLManager;
System.setProperty("javax.net.ssl.keyStore", "D:\\key\\client.p12");
System.setProperty("javax.net.ssl.keyStorePassword", "123456");
System.setProperty("javax.net.ssl.trustStore", "D:\\key\\client.truststore");
SSLManager.reset();
SSLManager.getInstance();

如上:里面执行了 SSLManager 的两个方法,这两个方式是在页面 SSL 管理器导入证书的时候触发,属于初始化的操作,因为我们不用他了,我们要主动去触发执行。
BeanShell 里面必须要用 System.setProperty 去设置,用他自带的 props 去设置,只代表是当前上下文的变量,不代表系统变量,${__serProperty("","")});也一样失效。
因为 Jmeter 是自带缓存机制的所以这个 Beanshell 执行一次就行了,我们采取仅一次执行器,如果放在前置处理器里面的话会每次都执行,所以要单独创建 beanshell 取样器
如下:


5.设置上面的之后我们就可以把路径等信息抽取出来,也可以通过一个 JMX 在多个 JMETER 都可以执行

共收到 13 条回复 时间 点赞

@taki 你好,第一步中 client.truststore 是怎么生成的呢?

@faith keytool -import -alias "my alipay cert" -file www.alipay.com.cert -keystore my.store
” my alipay cert” 是个别名,随便取。“www.alipay.com.cert” 这个文件就是从浏览器中导出的支付宝的证书。
“my.store” 是生成的自己 的证书库文件。回车执行,

这只是把服务端的证书给导上去了啊,但是客户端的呢?

@taki 你好 请问下
~/apache-jmeter-4.0/bin 目录下的 system.properties 关于 ssl 的配置

# SSL properties (moved from jmeter.properties)
#
# See http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#Customization
# for information on the javax.ssl system properties

# Truststore properties (trusted certificates)
#javax.net.ssl.trustStore=/path/to/[jsse]cacerts
#javax.net.ssl.trustStorePassword
#javax.net.ssl.trustStoreProvider
#javax.net.ssl.trustStoreType [default = KeyStore.getDefaultType()]

# Keystore properties (client certificates)
# Location
#javax.net.ssl.keyStore=.keystore
#
#The password to your keystore
#javax.net.ssl.keyStorePassword=changeit
#
#javax.net.ssl.keyStoreProvider
#javax.net.ssl.keyStoreType [default = KeyStore.getDefaultType()]

结合你此篇文章, 意思是

1 # Truststore properties 就是 服务端证书配置?
2 # Keystore properties (client certificates) 就是客户端证书配置?

我做了如下尝试:
比如https://www.jianshu.com 然后正则提取首页的 文章链接 进行遍历.
1 用 firefox 导出 jianshu.com 的证书 命名为 firefoxjianshucom.crt
2 将该 crt 转换为 truststore.jks
keytool -importcert -alias mycert -file firefoxjianshucom.crt -keystore truststore.jks -storepass mypasswd

http request 中的 client implementation 也已改为用 Java
3 然后通过 -D 执行我的 jmx
jmeter -Djavax.net.ssl.trustStore=/home/cmd/apache-jmeter-4.0/keyStore/truststore.jks -t jianshu.jmx

4 启动 jmeter gui 打开 option 下的 log viewer:

请问 哪里有错误.....ERROR o.a.j.u.SSLManager: Problem loading keystore: No key(s) found 怎么解决?

taki #5 · 2018年08月08日 Author
老马 回复


这里已经报错了

taki 回复

是的 这里 直接 复制 结果树里 拼接的文章 url 是可以直接访问的 说明正则和 jmeter 拼接正确,那就应该是 jmeter https 证书 这块的事情没有处理对,没有正确发送 https: 文章 url 请求....

我导入 和 转换 jianshu.com 浏览器端 也应该就是 客户端证书 是否操作有误?
无误的话 Log 显示 :
说明找到了该转换的 jks 但是里边的 key 内容有错

应该是这里 没有找到 我转换的 truststore.jks 里边的 key 值 我用命令
keytool -list -keystore 查看了 但这块不熟 也不知道 看到的内容 是不是正确.

taki #7 · 2018年08月08日 Author
老马 回复

ioexception 了,没有找到文件吧,你在好好检查路径什么的

僅樓主可見
taki 回复

解决了.... 一波三折 根本就不用什么证书 或者应该说 http request 里 implemetation 选择用 java 应该用的是
$JAVA_HOME/jre/lib/security/cacerts java 内置证书. 根本不用折腾导出 jianshu.com 的证书...

我的那个 Response data java.net.UnknownHostException 错误. 就是 http request 请求配置错误了.
server name or ip 只能写 www.jianshu.com 接的内容 写在 path ${article} 比如文章链接 path /p/8db213d15309
下 就正常了.

taki #10 · 2018年08月10日 Author
老马 回复

👍 👍 👍 赞,单项认证 httpclient 也可以绕过的

taki 回复

不过 log viewer 里的证书 keystore 还是有错误 我 添加了 ubuntu java 的 Truststore 也就是
/etc/ssl/certs/java/cacerts

(没有用 $JAVA_HOME/jre/lib/security/cacerts 这个路径 ubuntu18.04 下会有个错误
javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

参考这个解决:
https://stackoverflow.com/questions/6784463/error-trustanchors-parameter-must-be-non-empty
就是 sudo apt install ca-certificates-java
sudo update-java-alternatives -a
sudo update-ca-certificates -f
sudo /var/lib/dpkg/info/ca-certificates-java.postinst configure 等几个命令可以解决该报错
)

system.properties 配置:

# SSL properties (moved from jmeter.properties)
#
# See http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#Customization
# for information on the javax.ssl system properties

# Truststore properties (trusted certificates)
javax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts
#javax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/cacerts
javax.net.ssl.trustStorePassword=changeit
#javax.net.ssl.trustStoreProvider
#javax.net.ssl.trustStoreType [default = KeyStore.getDefaultType()]

# Keystore properties (client certificates)
# Location
#javax.net.ssl.keyStore=.keystore
javax.net.ssl.keyStore=/home/cmd/apache-jmeter-4.0/keyStore/jianshucom.jks
#
#The password to your keystore
#javax.net.ssl.keyStorePassword=changeit
javax.net.ssl.keyStorePassword=jianshucom
#javax.net.ssl.keyStoreProvider
#javax.net.ssl.keyStoreType [default = KeyStore.getDefaultType()]
javax.net.ssl.keyStoreType=JKS

但我的导出并转换的 jianshucom.jks kestore 还是会报错
ERROR o.a.j.u.SSLManager: Problem loading keystore: No key(s) found

然后,将该 jianshucom.crt 直接导出未转换的, 用 ketool 命令 导入 cacerts 如下操作:

sudo cp ~/apache-jmeter-4.0/keyStore/jianshucom.crt  /etc/ssl/certs/java/
​keytool -trustcacerts -keystore /etc/ssl/certs/java/cacerts -storepass changeit -importcert -alias jianshucom -file jianshucom.crt

# 查看条目 134 变135 说明添加进jianshucom了
keytool -list -keystore cacerts    

# 以下三条更新和修复 java certs 
sudo update-java-alternatives -a
sudo update-ca-certificates -f
sudo /var/lib/dpkg/info/ca-certificates-java.postinst configure

#再启动jmeter 还是报错
ERROR o.a.j.u.SSLManager: Problem loading keystore: No key(s) found

坛子里 谁能 详解下 Truststore properties Keystore properties 这快资料基本靠 *** 了解 太多了 还有各种证书的知识 jks crt 什么的....
http://www.cnblogs.com/princessd8251/articles/4326255.html
https://www.blazemeter.com/blog/how-set-your-jmeter-load-test-use-client-side-certificates
https://www.blazemeter.com/blog/how-to-use-multiple-certificates-when-load-testing-secure-websites
https://developer.ibm.com/mainframe/docs/how-to-test-your-apis/how-to-configure-jmeter-to-use-client-side-ssl/
https://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#Customization

https 主要有几种方案 一种是 jmeter 的代理证书

一种是用网站的 client-side certificate jks 单个证书的 详见 blazemeter 文章

一种是用 kestore confignation 来做 Multiple Certificates 多个证书的 详见 blazemeter 文章

taki 回复

truststore 是放信任的证书的一个 store
truststore 和 keystore 的性质是一样的,都是存放 key 的一个仓库,区别在于,truststore 里存放的是只包含公钥的数字证书,代表了可以信任的证书,而 keystore 是包含私钥的。

意思是 我从浏览器导出的 JIanshucom.crt 是个 keystore 但是我转换导入进 cacerts 的时候 我没带私钥密码 (我怎么会有 jianchucom 的私钥密码) 所以即使导入 cacerts 了 也是无法被找到 key 值? 所以报 Problem loading keystore: No key(s) found
?

老马 回复

https://confluence.atlassian.com/jira/connecting-to-ssl-services-117455.html

也许要效仿这个 是 confluence 教你如何导入证书的操作

需要 登录 後方可回應,如果你還沒有帳號按這裡 注册