我有一个访问控制的PHP系统,HTTP通过一个独特的安全模型将HTTP重定向到基于Java的报告系统(这很糟糕)。为了避开报告安全模型,我使用Tomcat过滤器在所有请求到达报告系统之前对其进行验证。我正在使用从PHP传递给Java的加密令牌,告诉报告系统谁是客户端。过滤器会根据受限列表检查请求的报告名称,如果客户端角色不足,则返回403。通过URL编码从PHP到Java的时间敏感加密/解密错误
加密的令牌存储时间戳和用户的角色,例如,
1365549482|SysAdmin
加密后,它看起来像这样
vSEFgBYd30Ik5p4PZlG968cvdg==
的PHP系统作为所有报告请求的代理。当用户请求报告时,请求会发送到PHP,PHP会生成一个加密的令牌,然后对其进行URL编码,然后将其附加到报告URL并向报告系统发出GET请求。我的Java过滤器解密令牌,将其拉开,并找出要执行的操作。
9倍于10这是好的,但偶尔令牌不能正确解密。上面的(未加密的)例子转换成这样的东西
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
)
);
的Java
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);
}
字符编码应该没有任何区别,因为酒吧字符(只)小于128,假设你的角色仅仅是ASCII字符串太多,但你知道什么编码你的PHP正在使用吗?我认为这里也只是64位编码,而不是URL编码。 – Rup 2013-04-10 00:14:54
这里还有一件奇怪的事情,就是你使用密钥的MD5哈希的字符串表示的字节,而不是密钥(!)的MD5哈希的字节。但我想这与PHP的MD5哈希函数以及mcrypt如何读取它一致? – Rup 2013-04-10 00:18:19
@Rup感谢输入,令牌是第一个64位编码的,但是因为它包含URL特殊字符(例如'='),所以它必须在被附加到报告请求URL之前进行URL编码。我不认为URL编码是这里的问题,但认为我会提到它的完整性。 – tomfumb 2013-04-10 00:29:14