2016-08-03 99 views
1

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

我想给bookingID使用Base64(编辑和mcrypt的)(希望这将是几乎不可能的猜测和访问其他用户的预订信息(虽然预订信息是不是真的过于敏感加密!) )。这样只有预定用户才能访问预订确认。

我使用的代码主要在这里找到(stackoverflow),因为我远离加密专家!

我有几个问题。 我使用的代码是下面和下面,这是我有

/** 
    * 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()给出了一个不同的加密字符串每个i使用它(即,对于相同的时间预订ID为123)。 只要它解密为相同,但每次加密字符串是否不相同都无关紧要。如果任何人都可以让我知道这是否应该每次都返回一个不同的字符串,我也会很感激,如果可以给出一个(容易理解的)解释为什么这是什么?

问题2: 上面的代码工作的大部分时间......(也许80%),但其他时候它不会解密正确的答案...我不明白为什么:-(如果。任何人都可以让我知道我在做什么错了,所以它工作时间的100%,我将非常感激

问题3:!(可能发行) 我使用进行urlencode()和urldecode()。我有很多关于stackoverflow的内容,并且无法解决,如果我应该使用这个或者不是!我怀疑问题2可能是由这个引起的,但是看不出来,然后做出正确的方法这个和URL是安全的。我曾尝试用类似下面的东西代替的URLEncode(在这里),但是这进而导致上述工作的时间

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

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

此外 0%是我使用允许的方法用户看到他们的预订细节确定/可取? (如上所述,数据不是很敏感,它只包括用户名,预订REF和预订的内容,当用户打开(酒店)预订时需要显示ID)。

任何帮助让我明白我在做什么(和加密)好一点是非常感激,甚至更多的赞赏,如果任何人都可以指出(这样我可以更正)我的方法中的错误将是伟大的! !

感谢您看这个:-) 福特

+0

@CharlotteDunois basee64_decode不“解密”(正如你所知)......它解码。福特:issue1不是问题..每次都会使用随机的“初始化向量”...导致不同的crypttext –

+0

@BradKent和其他发布者,我现在看到它有什么不同......简单,但我没有发现它直到它被指出:-) – Ford

+1

如果你使用[defuse/php-encryption](https://github.com/defuse/php-encryption),你可能会让你的生活变得更容易。 –

回答

1

如果任何人都可以让我知道这是否应该返回一个不同的字符串 每次和......为什么这是?

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

$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); 

所以结果每次都不一样。

上面的代码工作的大部分时间......(也许80%),但其他时候 它不会解密正确答案

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

我想给bookingID使用Base64(加密,希望它 几乎是不可能的猜测和访问其他用户预订 细节...是我使用,让用户看到的方法他们 预订信息OK

一个更好的办法是要求身份验证。您可以留下预约ID加密,但要求用户名&通保护用户显示您的预订细节之前

我同意认证是好,但我还需要允许 非注册用户

我会使用加密散列,并包括预约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参数会导致请求被拒绝,如果有人点击链接过多的时间过后。为了确保没有人改变了链接,就包括签名中的所有参数:

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

当您检查通过建立一个新的哈希签名,确保包括在同一顺序相同的参数

+0

谢谢!我同意认证是更好的,但我也需要允许非注册用户(我已经完成认证,但也需要这种方法:-() – Ford

+1

@Ford我在我的答案的末尾添加了一节告诉你如果认证不是一个选项我会怎么做 – BeetleJuice

+0

非常感谢你!!我会试试这个:-) – Ford

3

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

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

$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); 


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

或者,如果您不想让用户通过身份验证,则可以将随机ID绑定到足够随机/足够强大的预订,以防止强力攻击,并且在端点上限制速率。

$randomToken = bin2hex(openssl_random_pseudo_bytes(16)); 


你可以这样使用随机令牌来获取预订代替预约ID,/bookingconfirmation.php?bookingID=$randomToken。这比加密URL中的预订ID更好,更简单。

+0

谢谢,非常感谢。我也正在验证一些用户,但注册是可选的,所以我需要允许没有注册的成员访问。感谢您的回答,这听起来是一个很好的解决方案! – Ford

+2

那么是的,如果用户可以在没有注册的情况下进行预订,您将需要其他方法。我应该补充说,如果你为每个预订创建一个随机标记来检索它们,那么它们不能通过顺序标识访问,或者攻击者仍然可以行走它们。 –

+0

谢谢。我认为我understyand(/bookingconformation.php?bookingID=123不会返回任何结果(因为它会解密“123”的错误))。或者如你所说,我只匹配randomToken。如果这是你的意思? – Ford