2013-04-10 20 views
2

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

字符编码应该没有任何区别,因为酒吧字符(只)小于128,假设你的角色仅仅是ASCII字符串太多,但你知道什么编码你的PHP正在使用吗?我认为这里也只是64位编码,而不是URL编码。 – Rup 2013-04-10 00:14:54

+0

这里还有一件奇怪的事情,就是你使用密钥的MD5哈希的字符串表示的字节,而不是密钥(!)的MD5哈希的字节。但我想这与PHP的MD5哈希函数以及mcrypt如何读取它一致? – Rup 2013-04-10 00:18:19

+0

@Rup感谢输入,令牌是第一个64位编码的,但是因为它包含URL特殊字符(例如'='),所以它必须在被附加到报告请求URL之前进行URL编码。我不认为URL编码是这里的问题,但认为我会提到它的完整性。 – tomfumb 2013-04-10 00:29:14

回答

0

的问题可能是您的getBytes()方法 - 这些使用系统默认的字符编码,这是不能跨越每一个JVM相同。改用getBytes(“UTF-8”)。

+0

也许,但是如果键或IV被读错了,那么输出将看起来不像输入,而不是轻微损坏。 – Rup 2013-04-10 00:11:30

+0

我能想到的唯一的事情是,当输入使用一些Unicode字符时,键使用所有Ascii字符,在这种情况下,不管是Ascii还是UTF编码,键都是相同的,而输入会被破坏。无可否认,这是一个延伸。 – 2013-04-10 00:14:11

+0

Thanks @ Zim-ZamO'Pootertoot,我已经做出了您所建议的更改,至今我还没有看到该问题。我明天会大力测试,希望不会再看到它。 – tomfumb 2013-04-10 00:46:34

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); 
+0

我很欣赏这个输入,但是由于我不太了解安全方面,所以我不得不问 - 这能解释为什么我得到不一致的结果吗?这个问题最令人困惑的部分是它大部分时间工作的原因。事情似乎在'|'之前出现错误,在时间戳结束时,所以我认为有一个(或多个)'n |'的组合与这个字符串的处理方式有关。 – tomfumb 2013-04-10 15:38:34