2016-08-03 4 views
1

Мне нужно передать строку GET в электронное письмо, чтобы пользователь мог получить конкретную информацию о бронировании. i.e./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() дает другую строку шифрования, каждый раз, когда я его использовать (например, для того же bookingID от 123). Пока он расшифровывается до одного и того же, не имеет значения, является ли строка шифрования разной. Если кто-нибудь может сообщить мне, если это каждый раз будет возвращать другую строку, и я также был бы благодарен, если можно объяснить (легко понять) объяснение, почему это так?

Выпуск 2: Приведенный выше код работает большую часть времени .... (возможно, 80%), но в других случаях он не расшифровывает к правильному ответу ... я не понимаю, почему :-(если. кто-нибудь может, дайте мне знать, что я делаю неправильно, так что он работает на 100% времени, я был бы очень благодарен

выпуск 3: (возможный выпуск) я использую UrlEncode() и urldecode(). Я прочитал лоты на stackOverflow и не могу разобраться, если я должен использовать это или нет! Я подозреваю, что проблема 2 может быть вызвана этим, но не может видеть, как правильно выработать правильный способ это и безопасный URL. Я попытался заменить UrlEncode с чем-то подобным ниже (находится здесь), но это потом приводит к выше работе 0% время

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

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

Также метод я использую, чтобы позволить пользователь, чтобы посмотреть их данные о бронировании. ОК/желательно? (как уже упоминалось, данные не очень чувствительны, они включают только имя пользователя, бронирование REF и то, что было забронировано. ID должен отображаться, когда пользователь появляется для бронирования (гостиницы).

Любая помощь, позволяющая мне понять, что я делаю (и шифрование) немного лучше, ценится или даже более ценится, если кто-то может указать (чтобы я мог исправить) ошибки в моем методе были бы замечательными! !

Спасибо за глядя на это :-) Форд

+0

@CharlotteDunois basee64_decode не «расшифровывает» (как вы знаете) ... он декодирует. Ford: issue1 не проблема .. случайный «вектор инициализации» используется каждый раз ... в результате получается другой криптотекст –

+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 в незашифрованном виде, но защитить пользователя, требуя имя пользователя & пройти, прежде чем показать детали бронирования

я согласен аутентификация лучше, но я также необходим обеспечить незарегистрированных пользователей

Я хотел бы использовать шпоночное хэш, и включаю в себя как идентификатор заказа и хэш в URL. Тогда будет легко узнать, когда пользователь пытается получить доступ к чужому бронированию.

Настройка 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-адресе также больше не является проблемой, так как вы можете проверить его против пользователя.

В качестве альтернативы вы можете связать случайный идентификатор с заказом, который достаточно случайный/достаточно сильный, чтобы предотвратить атаку грубой силы в сочетании с ограничением скорости на конечной точке, если вы не хотите, чтобы пользователь был аутентифицирован.

$randomToken = bin2hex(openssl_random_pseudo_bytes(16)); 


Вы бы затем использовать случайный маркер для выборки номера вместо бронирования ID, /bookingconfirmation.php?bookingID=$randomToken. Это лучший и более простой подход, чем шифрование идентификатора бронирования в URL-адресе.

+0

спасибо, много оценен. Я также проверяю некоторых пользователей, но регистрация не является обязательной, поэтому мне не нужно позволять ни одному зарегистрированному члену доступа. спасибо за ваш ответ, это звучит неплохо! – Ford

+2

Ах, тогда да, если пользователь может сделать заказ без регистрации, вам понадобится другой метод. Я должен добавить тогда, если вы спуститесь по пути создания случайного токена для каждого бронирования, чтобы получить их, они не могут быть доступны через последовательный идентификатор, или злоумышленник все равно сможет их пропустить. –

+0

спасибо. я думаю, что я понял (/bookingconformation.php?bookingID=123 не вернул никаких результатов (так как он расшифровал бы «123» на что-то неправильное)). или, как вы говорите, я только матч на randomToken. если это то, что вы имеете в виду? – Ford