2016-08-03 101 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