了解使用 base64 和 mcrypt 的加密

Understanding encryption with base64 and mcrypt

我需要将 GET 字符串传递给电子邮件,以允许用户访问特定的预订详细信息。 即 /bookingconformation.php?bookingID=123.

我正在尝试使用 base64(edit 和 mcrypt)加密 bookingID(希望几乎不可能猜测和访问其他用户的预订详细信息(尽管预订细节并不太敏感!))。这样只有目标用户才能访问预订信息。

我使用的代码主要在此处 (Whosebug),因为我远不是加密专家!!

我有一些问题。 我正在使用的代码在下面,下面是我遇到的问题列表

/**
    * a basic encryption for things like IDs, so links can be created and emailed to i.e booking details
    * @param int/str $x what is to be encrypted
    * @ENCRYPTION_KET str the encyption key
    * @return encrypted string
    */
    public static function basicEncrypt($x, $ENCRYPTION_KET) {
        $key = pack('H*', $ENCRYPTION_KET);
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $x, MCRYPT_MODE_CBC, $iv);
        $ciphertext = $iv . $ciphertext;
        $ciphertext_base64 = base64_encode($ciphertext);
        $encrypted_x = urlencode($ciphertext_base64);
        return $encrypted_x;
    }

    /**
    * a basic de-cryption for things like IDs, so links can be created and emailed to i.e booking details
    * @param str $x what is to be de-crypted
    * @ENCRYPTION_KET str the encyption key
    * @return decrypted string
    */
    public static function basicDecrypt($x, $ENCRYPTION_KET) {      
        $x = urldecode($x);     
        $ciphertext_dec = base64_decode($x);        
        $key = pack('H*', $ENCRYPTION_KET);
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $iv_dec = substr($ciphertext_dec, 0, $iv_size);
        $ciphertext_dec = substr($ciphertext_dec, $iv_size);
        $de_crypted_x = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
        return $de_crypted_x;       
    }

问题 1: 使用 basicEncrypt() 每次我使用它时都会给出不同的加密字符串(即对于相同的预订 ID 123)。 只要它解密为相同的,每次加密字符串是否不同都没有关系。如果有人可以让我知道这是否应该 return 每次都是不同的字符串,如果可以给出(易于理解的)解释为什么会这样,我也将不胜感激?

第 2 期: 上面的代码大部分时间都有效....(可能是 80%)但其他时候它不会解密为正确的答案...我不明白为什么 :-(。如果有人可以让我知道我做错了什么以便它在 100% 的时间内工作,我将不胜感激!

问题 3:(可能的问题) 我正在使用 urlencode() 和 urldecode()。我已经阅读了很多关于 Whosebug 的文章,但不知道我是否应该使用它!我怀疑 问题 2 可能由此引起,但无法找出正确的方法来做到这一点并 URL 安全。我尝试用类似于下面的东西(在此处找到)替换 URLencode,但这会导致上面的工作时间为 0%

function base64_url_encode($input) {
 return strtr($input, '+/=', '-_,');
}

function base64_url_decode($input) {
 return strtr($input, '-_,', '+/=');
}

此外, 是我用来让用户查看其预订详细信息的方法 OK/advisable? (如前所述,数据并不是很敏感,它只包括用户名、预订 REF 和预订的内容。当用户出现(酒店)预订时需要显示 ID)。

任何能让我更好地理解我在做什么(和加密)的帮助都非常感谢,如果有人能指出(这样我就可以纠正)我的方法中的错误,那就太好了!!

感谢您看到这里 :-) 福特

首先,base64()与加密无关,它是一种编码,不应该用于任何类型的保护。请不要在同一句话中使用这些术语!

加密每次提供不同输出的原因是您为每次加密使用随机 IV。

$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);


为什么在用户点击预订确认端点时对用户进行身份验证会出现问题?他们可以访问 /bookingconfirmation.php?bookingID=123 并且要么已经通过身份验证,要么必须登录才能查看预订。这似乎是最好和最安全的选择。 URL 中的 ID 也不再是问题,因为您可以根据用户对其进行验证。

或者,您可以将随机 ID 绑定到足以 random/strong 足以防止暴力攻击的预订,并在端点上限制速率,如果您不想让用户得到认证。

$randomToken = bin2hex(openssl_random_pseudo_bytes(16));


然后您将使用随机令牌而不是预订 ID 来获取预订,/bookingconfirmation.php?bookingID=$randomToken。与在 URL.

中加密预订 ID 相比,这是一种更好、更简单的方法

If anyone can let me know if this should return a different string each time and...to why this is?

加密结果由加密密钥、明文和初始化向量(iv)决定。由于此行,每次加密时都会随机构建 iv:

$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

所以每次的结果也不一样

The above code works MOST of the time.... (maybe 80%) but other times it does not decrypt to the correct answer

我不知道那是什么。 url encoding/decoding 应该足够了;我认为不需要 base64 编码。请确保以正确的顺序进行:先加密,然后在写入时进行编码。读时先解码再解密

I am trying to encrypt the bookingID with base64 (in the hope that it will be nearly impossible to guess and access other users booking details...is the method i am using to allow the user to see their booking details OK

更好的方法是要求身份验证。您可以不加密预订 ID,但在显示预订详细信息之前要求用户名和密码以保护用户

i agree authentication is better, but i also need to allow for non-registered users

我会使用键控哈希,并在 url 中包含预订 ID 和哈希。这样就很容易知道用户何时试图访问其他人的预订。

设置URL:

//hash will always be the same for the same booking id, but impossible to guess
$hash = hash_hmac('sha256',$bookingID,$SECRET_KEY);

//url includes both the booking id and the hash
$url = "http://example.com/confirm.php?id=$bookingID&sig=$hash";

在显示预订详情之前,请确保哈希值正确无误:

if(!isset($_GET['id'],$_GET['sig'])){
    http_response_code(400); //tells the browser that the request is malformed
    echo "Missing booking id or signature";
    exit;
}
$bookingID = $_GET['id'];
$sig = $_GET['sig'];
$correct_hash = hash_hmac('sha256',$bookingID,$SECRET_KEY);

//if anyone modifies the url, the sig will not equal the correct hash
if($sig!==$correct_hash){
    http_response_code(400);
    echo "Invalid signature";
    exit;
}
//we get here if the sig matched the booking ID. Show booking details

使用此技术,您可以在 URL 中添加更多信息,例如 expires 参数,如果有人在点击 link 后点击过多,该参数将导致请求被拒绝时间过去了。为确保没有人更改 link,只需在签名中包含所有参数:

$hash = hash_hmac('sha256',"$bookingID.$expires",$SECRET_KEY);

当您通过构建新的散列来检查签名时,请确保以相同的顺序包含相同的参数