2

我有一个访问控制的 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);
}
4

2 回答 2

0

问题可能出在您的 getBytes() 方法上——这些方法使用默认的系统字符编码,这在每个 JVM 中都不相同。请改用 getBytes("UTF-8")。

于 2013-04-10T00:09:41.707 回答
0

我认为问题在于您如何在 PHP 中使用 mcrypt 库,然后对加密数据进行 base64 编码?我们在做类似的事情时肯定遇到了一些问题,并放弃了 base64 编码,然后它就起作用了。

您可以使用另一种方法来传递令牌而不是 url 吗?例如 cookie 或 auth 标头?

这是我在 PHP 中加密/解密的片段(我对 Java 不是很好),因为我认为您的 mcrypt 不正确。

编码:

    $userObjectJson = json_encode($this);

    //encrypt the user session object
    $mcrypt = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CFB, '');
    $_SESSION['iv'] = mcrypt_create_iv(mcrypt_enc_get_iv_size($mcrypt), MCRYPT_RAND);
    $keySize = mcrypt_enc_get_key_size($mcrypt);
    $key = substr(MYAWESOME_KEY, 0, $keySize);

    mcrypt_generic_init($mcrypt, $key, $_SESSION['iv']);
    $_SESSION['user'] = mcrypt_generic($mcrypt, $userObjectJson);
    mcrypt_generic_deinit($mcrypt);
    mcrypt_module_close($mcrypt);

解码:

    //decrypt the user session object
    $mcrypt = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CFB, '');
    $keySize = mcrypt_enc_get_key_size($mcrypt);
    $key = substr(MYAWESOME_KEY, 0, $keySize);
    mcrypt_generic_init($mcrypt, $key, $_SESSION['iv']);
    $userObjectJson = mdecrypt_generic($mcrypt, $_SESSION['user']);
    mcrypt_generic_deinit($mcrypt);
    mcrypt_module_close($mcrypt);
于 2013-04-10T00:53:43.553 回答