我有一个访问控制的 PHP 系统,HTTP 将客户端重定向到具有独特安全模型的基于 Java 的报告系统(这很糟糕)。为了绕过报告安全模型,我使用 Tomcat 过滤器在所有请求到达报告系统之前对其进行验证。我正在使用从 PHP 传递到 Java 的加密令牌,它告诉报告系统客户端是谁。过滤器根据限制列表检查请求的报告名称,如果客户端的角色不足,则返回 403。
加密令牌存储时间戳和用户角色,例如
1365549482|SysAdmin
加密后看起来像这样
vSEFgBYd30Ik5p4PZlG968cvdg==
PHP 系统充当所有报告请求的代理。当用户请求报告时,请求转到 PHP,PHP 生成加密令牌,URL 对其进行编码,然后将其附加到报告 URL 并向报告系统发出 GET 请求。我的 Java 过滤器对令牌进行解密,将其拆开,然后弄清楚要做什么。
10 次中有 9 次都可以,但有时无法正确解密令牌。上面的(未加密的)例子被转换成这样的
1365549482q??YZ7
一切都出错了。
我对加密、解密和字符编码的细节有点不了解,但不幸的是,我是唯一可以从事此工作的开发人员。任何关于这里可能出现问题的想法都将不胜感激。我不期望有任何大的代码更改,因为它在大多数时间都有效,但显然其中有一个我不理解的时间敏感组件。下面的代码片段
编辑
我现在已经花了一段时间调试它,但它变得陌生了。我编写了一个小型 Java 程序,通过 HTTP GET 从 PHP 请求令牌。PHP 脚本返回与在正常工作流程中通过 URL 参数传递给 Java 的相同(URL 编码)值。Java 程序以与下面的代码片段相同的方式对此进行解码和解密,并检查结果。经过数千次迭代(到目前为止,还在不断增加),它按预期工作。但是,在进行此测试时,我可以在过滤器的日志文件中看到相同的故障。
导致此间歇性问题的原因似乎与作为 Tomcat 过滤器的 Java 类或通过 Tomcat 通过 URL 传递的数据有关。这是否给任何人暗示这里可能发生的事情?我现在很困惑。
PHP
$presentAsSeconds = time();
$message = strval($presentAsSeconds + Configure::read('Reporting.Authentication.ExpireInSeconds')) . '|' . $userDetails['role'];
return base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
md5(Configure::read('Reporting.Authentication.Key')), // matches "the key" in Java function
$message,
MCRYPT_MODE_CFB,
Configure::read('Reporting.Authentication.IVector') // matches "the vector" in Java function
)
);
爪哇
private String decrypt(String initial) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(md5("the key").getBytes("UTF-8"), "AES");
IvParameterSpec initialVector = new IvParameterSpec("the vector".getBytes("UTF-8"));
Cipher cipher = Cipher.getInstance("AES/CFB8/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, initialVector);
byte[] encryptedByteArray = (new org.apache.commons.codec.binary.Base64()).decode(initial.getBytes("UTF-8"));
byte[] decryptedByteArray = cipher.doFinal(encryptedByteArray);
return (new String(decryptedByteArray, "UTF8"));
}
private String md5(String input) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest(input.getBytes("UTF-8"));
BigInteger number = new BigInteger(1, messageDigest);
return number.toString(16);
}