在进入正题之前,我想还是有必要再尽量简洁地唠叨一遍一些有关HTTPS工作原理方面的知识,了解这些技术细节有利于你明白为什么JMeter在录制时要求你进行一系列的准备和配置工作,以及它是如何完成这项测试任务的。而且,在不了解原理的情况下开展相关技术领域的测试工作,可能是一件非常“危险”的事情,如果你已经了解了HTTPS的工作原理,你可以跳过此章节。
众所周知,加密算法主要分为对称和非对称加密,对称加密就是大家使用相同的密钥完成加解密,这也是人类历史上长期运用的消息安全传递方法,这个方法有一个明显的缺点就是密钥的唯一性所带来的可能出现多个异地保存的副本,比如一份密码本对于消息的加解密人员必须人手一份才能正常完成工作,一旦有一份密码本泄露出去到了第三方的手中,加密体系的保密性也就不复存在了。
随着数学和计算机技术的发展,人们终于发明了非对称加密算法以解决密钥的唯一性问题,这时产生了一对密钥,这对密钥可以实现相互加解密。你可以将一份密钥(私钥)掌握在自己手中,将另一份密钥(公钥)放出去,其他人得到公钥,用公钥对信息进行加密后发送给你,你就可以用手中的私钥对消息进行解密,你也可以反向用自己的私钥加密信息发给其他掌握了公钥的人,他们用公钥来解密你的加密信息。在非对称加密体系中,你只需要照顾好自己手中的私钥不要遗失,不用担心公钥的泄露会造成安全隐患。另外,非对称加密算法的好处远远超过了只是消息加密的范畴,当消息发送方手中牢牢掌握了自己的私钥的时候,消息接收方有理由相信,当他使用发送方给他的公钥成功完成消息解密的同时,发送方的身份也就得到的验证。但更加安全的代价就是非对称加密算法的性能相对于对称加密算法要慢得多。
有人会说既然有了非对称加密算法,那么直接利用它就可以实现浏览器与Web服务器间通信消息的加解密了。但你要明白一切保障信息安全的手段都是在牺牲性能和易用性的代价下展开的,确实可以在消息传递中直接利用非对称加密算法来实现消息的加解密,但在浏览器与Web服务器之间HTTP协议如此频繁和体积巨大的消息通信场景下,非对称加密算法的性能问题就凸显出来,如果直接采用,将极大影响协议的整体性能。于是,人们就采用变通的方法,同时利用非对称加密算法和对称加密算法实现针对HTTP消息传递的加解密,其中非对称加密算法只参与到对对称加密算法密钥(对话密钥)的加密过程中,而大块消息的加解密则由浏览器和Web服务器间协商好的对称加密算法来完成。
另外,任何Web服务器都有可能向浏览器提供建立HTTPS连接所需要的公钥,这里就排除不了一些假冒的服务器提供一些自己伪造的公钥,为了确保Web服务器是值得我浏览器信任的,于是引入了数字证书的概念。为了证明自己是值得信赖的,Web服务器需要向第三方CA机构申请一个数字证书,证书中包含了证书基本信息和服务器的公钥信息,证书的最后面是一个由CA机构的私钥对证书上述信息计算摘要后加密的消息签名信息。浏览器内置了一些权威的根证书,这些根证书中带有对应其发证CA机构的公钥,一旦得到Web服务器的数字证书,浏览器会在第一时间来根据证书信息查找是否存在对应的根证书,如果存在,利用根证书中的公钥解密Web服务器数字证书中的消息签名信息,并与自己计算的证书摘要信息进行比对,从而验证其真实性和完整性,只要通过验证,浏览器会自动信任由这些权威机构颁发的证书。当然在某些特定场景下Web服务器也需要浏览器提供数字证书以证明其可信度。
HTTPS采用SSL/TLS协议实现在通信安全上的保障,主要分为握手阶段和对话阶段。
其中握手阶段的大致的工作流程如下:
(1)首先,浏览器会向服务器发起HTTPS请求,请求消息中包含了自己当前所采用的SSL/TLS协议的版本信息,一个随机数(用于生成在对话阶段的对称加密密钥)支持的加密算法。另外,还将向服务器索要数字证书;
(2)服务器回应浏览器的请求,响应消息中包含确认使用与浏览器相同版本的SSL/TLS协议的回应,一个随机数(用于生成在对话阶段的对称加密密钥),确认将使用浏览器支持的加密算法完成加解密。并将数字证书发给浏览器;
(3)浏览器接到服务器的数字证书后,判断其是否值得信任,如果信任,获取服务器的公钥,将生成一个随机数(用于生成在对话阶段的对称加密密钥)并使用服务器提供的公钥进行加密,向服务器发送请求消息,请求消息中包含了加密后的随机数,编码改变的通知(表示随后的信息都将用双方商定的加密方法和密钥发送),浏览器握手阶段结束的通知(包含一个之前所有信息的摘要值以校验是否握手阶段通信信息完整)。
(4)服务器确认通知,通过自己的私钥解密被加密随机数,并回应浏览器的请求,响应消息为编码改变的通知(表示随后的信息都将用双方商定的加密方法和密钥发送),服务器握手阶段结束的通知(包含一个之前所有信息的摘要值以校验是否握手阶段通信信息完整)。
对话阶段就将采用由三次产生随机数所生成的对称加密密钥对HTTP消息进行加解密的传输。
Keytool 是一个Java数字证书的管理工具,为我们提供了便捷的方法来制作、管理数字证书。主要的使用方法如下:
(1)制作证书
keytool -genkey -alias xreztento -sigalg MD5withRSA -keyalg RSA -keysize 1024 -validity 10950 -keystore ./test.keystore
可以使用-sigalg指定消息签名算法,比如MD2withRSA、MD5withRSA、SHA1withRSA等。可以使用-keyalg指定非对称加密算法,比如RSA、DSA等。
如果是初次创建keystore,将要求你设置密码信息,之后填写证书信息后完成证书的生产:
(2)查看基本信息
keytool -list -v -keystore ./test.keystore
我们就可以看到在keystore中全部证书的基本信息情况,比如消息签名算法,证书指纹等:
(3)查看公钥信息
keytool -list -rfc -keystore ./test.keystore
我们就可以看到在keystore中全部证书的公钥:
(4)导出数字证书
keytool -export -file xreztento.crt -alias xreztento -keystore ./test.keystore
我们导出指定的数字证书:
(5)导出私钥
You can extract a private key from a keystore with Java6 and OpenSSL. This all depends on the fact that both Java and OpenSSL support PKCS#12-formatted keystores.
Next, use OpenSSL to do the extraction to PEM.
我们可以先将证书仓库转换为PKCS12格式,然后利用OpenSSL自带的工具进行私钥的导出:
keytool -importkeystore -srckeystore test.keystore -destkeystore test.p12 -deststoretype PKCS12
导出结果如下:
openssl pkcs12 -in test.p12 -out extracted.pem -nodes
从而导出私钥:
下面,我们就通过Keytool生产的数字证书,来搭建一个基于Apache Tomcat的测试环境,主要的配置非常简单,就是在server.xml文件下增加一个HTTPS的连接器配置项,如下:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="D:\keystore\test.keystore"
keystorePass="123456"
ciphers="xreztento"/>
这样我们就完成了配置工作,现在启动Tomcat,使用8443端口访问:
可以看到我们生产的证书由于浏览器没有找到对应的内置根证书,所以警告用户这个HTTPS连接是不可信的,我们通过“高级”下的继续访问强行通过:
至此,测试环境准备完成。
For versions of JMeter from 2.10, JMeter will generate its own certificate(s). These are generated with a validity period defined by the property proxy.cert.validity , default 7 days, and random passwords. If JMeter detects that it is running under Java 7 or later, it will generate certificates for each target server as necessary (dynamic mode) unless the following property is defined: proxy.cert.dynamic_keys=false . When using dynamic mode, the certificate will be for the correct host name, and will be signed by a JMeter-generated CA certificate.
JMeter2.10版本+Java7以上版本很好的支持了HTTPS的录制,我们知道JMeter录制是通过浏览器访问其代理服务器,由代理服务器根据访问解析后生成HTTPSampler的方式完成录制的。代理服务器对于浏览器来说是充当了Web服务器的角色,对于Web服务器来说充当了浏览器的角色,于是当建立代理服务器连接后,浏览器会直接将代理服务器当做目标Web服务器,还记得我们普及的HTTPS原理知识吗,它就会向代理服务器索要数字证书,于是,JMeter通过生成一个本地证书的方式来完成这个与浏览器建立HTTPS握手阶段的过程。
当启动代理服务器时,JMeter会生产一个证书:
所生产的证书在bin目录下:
显然,我们的JMeter数字证书也是不被信任的,接下来我们就需要将该证书导入到浏览器的根证书列表中以达到人工配置信任的目的:
完成导入后,重新启动浏览器,我们再重新录制脚本:
于是,我们录制成功,回放一下:
这样,我们就完成了基于HTTPS的录制,以上基于对HTTPS工作原理的理解所完成的操作可以完美的实现录制工作,当然,在某些浏览器环境下,你也可以不选择导入证书的环节,而是直接将站点域名作为信任站点加入到信任列表中。
录制完脚本,回放就一定可以成功吗?在大多数情况下,我们都可以成功的完成回放及后续的测试工作,但事事不绝对,你可能会遇到一些奇异的问题,比如,当你制作数字证书时,使用了以下命令,我们将消息签名算法修改为MD2withRSA:
keytool -genkey -alias xreztento -sigalg MD2withRSA -keyalg RSA -keysize 1024 -validity 10950 -keystore ./test.keystore
什么原因造成的问题呢?
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
Cause:
JDK7 has changed the default Java security settings to disable MD2 algorithm to sign SSL certificates.
Resolving the problem:
The default Java security settings can be re-enabled by editing JDK_HOME/jre/lib/security/java.security and commenting out the following line:
\jdk.certpath.disabledAlgorithms=MD2
原因是JDK7以上版本的默认安全策略有所加强,凡是签名算法为MD2的都不符合其默认要求,因此,为你提供了两种途径来修复该问题:
(1)修改java.security文件的安全策略
(2)直接将JRE版本调整为Java6