ঠিক আছে, আমাকে এই ভোঁতাভাবে বলতে দাও: আপনি যদি এই উদ্দেশ্যে ব্যবহারকারীর ডেটা বা ব্যবহারকারীর ডেটা থেকে প্রাপ্ত কোনও কুকির মধ্যে রাখেন তবে আপনি কিছু ভুল করছেন।
সেখানে। এটা আমি বলেছি. এখন আমরা আসল উত্তরের দিকে যেতে পারি।
হ্যাশিং ব্যবহারকারীর ডেটাতে কি সমস্যা হয়েছে, আপনি জিজ্ঞাসা করছেন? ঠিক আছে, এটি অস্পষ্টতার মাধ্যমে এক্সপোজার পৃষ্ঠ এবং সুরক্ষা নেমে আসে।
এক সেকেন্ডের জন্য কল্পনা করুন যে আপনি আক্রমণকারী। আপনি আপনার সেশনে আমাকে মনে রাখার জন্য একটি ক্রিপ্টোগ্রাফিক কুকি সেট দেখতে পান। এটি 32 অক্ষর প্রশস্ত। ঘি। এটি এমডি 5 হতে পারে ...
আসুন এক সেকেন্ডের জন্য কল্পনাও করুন যে তারা যে অ্যালগরিদমটি ব্যবহার করেছেন তা তারা জানে। উদাহরণ স্বরূপ:
md5(salt+username+ip+salt)
এখন, সমস্ত আক্রমণকারীকে "নুন" (যা আসলে লবণ নয়, তবে এরপরে আরও বেশি পরিমাণে) জোর করা উচিত, এবং তিনি এখন তার আইপি ঠিকানার জন্য যে কোনও নকল টোকেন ব্যবহার করতে চান তা তৈরি করতে পারেন! কিন্তু নিষ্ঠুর-জোর করে নুন দেওয়া শক্ত, তাই না? একেবারে। তবে আধুনিক সময়ের জিপিইউগুলি এতে দুর্দান্ত। এবং যদি আপনি এতে পর্যাপ্ত এলোমেলো ব্যবহার না করেন (এটিকে যথেষ্ট বড় করে তুলুন), এটি দ্রুত পতিত হতে চলেছে এবং এটি দিয়ে আপনার দুর্গের চাবিগুলি রয়েছে।
সংক্ষেপে, আপনাকে রক্ষা করার একমাত্র জিনিস হ'ল লবণ, যা সত্যই আপনাকে যতটা ভাবেন তেমন রক্ষা করে না।
কিন্তু অপেক্ষা করো!
এর সবই অনুমান করা হয়েছিল যে আক্রমণকারী অ্যালগোরিদম জানে! যদি এটি গোপন এবং বিভ্রান্তিকর হয় তবে আপনি নিরাপদ, তাই না? ভুল । ভাবনার এই লাইনের একটি নাম রয়েছে: অস্পষ্টতার মাধ্যমে সুরক্ষা , যা কখনও নির্ভর করা উচিত নয় ।
ভাল উপায়
সর্বোত্তম উপায় হ'ল আইডি ব্যতীত কোনও ব্যবহারকারীর তথ্য কখনও সার্ভার ছেড়ে না দেওয়া।
যখন ব্যবহারকারী লগ ইন করে, একটি বড় (128 থেকে 256 বিট) এলোমেলো টোকেন উত্পন্ন করে। এটি একটি ডেটাবেস টেবিলটিতে যুক্ত করুন যা ইউজারিডে টোকেনটি মানচিত্র করে এবং তারপরে এটি কুকির ক্লায়েন্টকে প্রেরণ করে।
আক্রমণকারী যদি অন্য ব্যবহারকারীর এলোমেলো টোকেনটি অনুমান করে তবে কী হবে?
আচ্ছা, এখানে কিছু গণিত করা যাক। আমরা একটি 128 বিট এলোমেলো টোকেন তৈরি করছি। এর অর্থ এখানে রয়েছে:
possibilities = 2^128
possibilities = 3.4 * 10^38
এখন, এই সংখ্যাটি কতটা অযৌক্তিকভাবে বড় তা দেখানোর জন্য আসুন ইন্টারনেটে প্রতিটি সার্ভারটি কল্পনা করুন (আসুন আজ ৫০,০০,০০০ বলি) প্রতি সেকেন্ডে ১,০০,০০,০০০ হারে এই সংখ্যাটিকে জোর করে চালানোর চেষ্টা করছি। বাস্তবে আপনার সার্ভারগুলি এ জাতীয় বোঝার নীচে গলে যাবে তবে আসুন এটি খেলি।
guesses_per_second = servers * guesses
guesses_per_second = 50,000,000 * 1,000,000,000
guesses_per_second = 50,000,000,000,000,000
সুতরাং প্রতি সেকেন্ডে 50 কোয়াড্রিলিয়ান অনুমান। তাড়াতাড়ি! রাইট?
time_to_guess = possibilities / guesses_per_second
time_to_guess = 3.4e38 / 50,000,000,000,000,000
time_to_guess = 6,800,000,000,000,000,000,000
সুতরাং 6.8 সেক্সটিলিওন সেকেন্ড ...
এটিকে আরও বন্ধুত্বপূর্ণ সংখ্যায় নামানোর চেষ্টা করি।
215,626,585,489,599 years
বা আরও ভাল:
47917 times the age of the universe
হ্যাঁ, এই মহাবিশ্বের বয়স 47917 গুণ ...
মূলত, এটি ক্র্যাক হবে না।
সুতরাং সংক্ষেপে:
আমি প্রস্তাবিত আরও ভাল পদ্ধতির হ'ল কুকিটি তিনটি অংশে সঞ্চয় করা।
function onLogin($user) {
$token = GenerateRandomToken(); // generate a token, should be 128 - 256 bit
storeTokenForUser($user, $token);
$cookie = $user . ':' . $token;
$mac = hash_hmac('sha256', $cookie, SECRET_KEY);
$cookie .= ':' . $mac;
setcookie('rememberme', $cookie);
}
তারপরে, যাচাই করতে:
function rememberMe() {
$cookie = isset($_COOKIE['rememberme']) ? $_COOKIE['rememberme'] : '';
if ($cookie) {
list ($user, $token, $mac) = explode(':', $cookie);
if (!hash_equals(hash_hmac('sha256', $user . ':' . $token, SECRET_KEY), $mac)) {
return false;
}
$usertoken = fetchTokenByUserName($user);
if (hash_equals($usertoken, $token)) {
logUserIn($user);
}
}
}
দ্রষ্টব্য: আপনার ডাটাবেসে একটি রেকর্ড দেখার জন্য ব্যবহারকারী এবং টোকেনের টোকেন বা সংমিশ্রণটি ব্যবহার করবেন না। ব্যবহারকারীর উপর ভিত্তি করে সর্বদা রেকর্ড আনার বিষয়ে নিশ্চিত হন এবং পরে আনা টোকেনটির তুলনা করার জন্য একটি সময়-নিরাপদ তুলনা ফাংশন ব্যবহার করুন। সময় আক্রমণ সম্পর্কে আরও ।
এখন, এটি খুব গুরুত্বপূর্ণ যে SECRET_KEY
একটি ক্রিপ্টোগ্রাফিক সিক্রেট (যেমন /dev/urandom
কোনও কিছু দ্বারা উত্পন্ন এবং / অথবা উচ্চ-এনট্রপি ইনপুট থেকে প্রাপ্ত)। এছাড়াও, GenerateRandomToken()
একটি শক্তিশালী র্যান্ডম উৎস হওয়া প্রয়োজন ( mt_rand()
প্রায় শক্তিশালী যথেষ্ট নয়। যেমন একটি লাইব্রেরি ব্যবহার করুন RandomLib বা random_compat , অথবা mcrypt_create_iv()
সঙ্গে DEV_URANDOM
) ...
hash_equals()
প্রতিরোধ করা হয় সময়জ্ঞান আক্রমণের । আপনি যদি পিএইচপি 5.6 এর নীচে পিএইচপি সংস্করণ ব্যবহার করেন তবে ফাংশনটি hash_equals()
সমর্থিত নয়। hash_equals()
এক্ষেত্রে আপনি টাইমিংসেফকম্পিয়ার ফাংশনটি প্রতিস্থাপন করতে পারেন :
/**
* A timing safe equals comparison
*
* To prevent leaking length information, it is important
* that user input is always used as the second parameter.
*
* @param string $safe The internal (safe) value to be checked
* @param string $user The user submitted (unsafe) value
*
* @return boolean True if the two strings are identical.
*/
function timingSafeCompare($safe, $user) {
if (function_exists('hash_equals')) {
return hash_equals($safe, $user); // PHP 5.6
}
// Prevent issues if string length is 0
$safe .= chr(0);
$user .= chr(0);
// mbstring.func_overload can make strlen() return invalid numbers
// when operating on raw binary strings; force an 8bit charset here:
if (function_exists('mb_strlen')) {
$safeLen = mb_strlen($safe, '8bit');
$userLen = mb_strlen($user, '8bit');
} else {
$safeLen = strlen($safe);
$userLen = strlen($user);
}
// Set the result to the difference between the lengths
$result = $safeLen - $userLen;
// Note that we ALWAYS iterate over the user-supplied length
// This is to prevent leaking length information
for ($i = 0; $i < $userLen; $i++) {
// Using % here is a trick to prevent notices
// It's safe, since if the lengths are different
// $result is already non-0
$result |= (ord($safe[$i % $safeLen]) ^ ord($user[$i]));
}
// They are only identical strings if $result is exactly 0...
return $result === 0;
}