سؤال

أقوم بتشغيل موقع ويب ، وهناك نظام تسجيل يمنحك نقاطًا لعدد المرات التي تلعب فيها لعبة.

إنه يستخدم التجزئة لإثبات سلامة طلب HTTP للتسجيل حتى لا يتمكن المستخدمون من تغيير أي شيء ، ولكن كما كنت أخشى أن يحدث شخص ما ، فقد اكتشف شخص ما أنه لا يحتاج إلى تغييره ، بل يحتاجون فقط إلى الحصول على درجة عالية ، وتكرار طلب HTTP ، والرؤوس وجميع.

في السابق ، منعت من الحماية من هذا الهجوم لأنه كان من غير المحتمل. ومع ذلك ، الآن بعد أن حدث ، أستطيع. ينشأ طلب HTTP من لعبة فلاش ، ثم يتم التحقق من صحته بواسطة PHP و PHP يدخلها إلى قاعدة البيانات.

أنا متأكد من أن عدم الحالات ستحل المشكلة ، لكنني لست متأكدًا تمامًا من كيفية تنفيذها. ما هي طريقة شائعة وآمنة لإعداد نظام غير CON؟

هل كانت مفيدة؟

المحلول

من السهل جدًا فعل ذلك ... هناك بعض المكتبات للقيام بذلك من أجلك:

  1. مكتبة PHP nonce
  2. مكتبة OpenID nonce

أو إذا كنت ترغب في كتابة بنفسك ، فهذا أمر بسيط للغاية. باستخدام صفحة ويكيبيديا كنقطة انطلاق ، في الكود الزائف:

على جانب الخادم ، تحتاج إلى وظيفتين قابلتين للاتصال بالعميل

getNonce() {
    $id = Identify Request //(either by username, session, or something)
    $nonce = hash('sha512', makeRandomString());
    storeNonce($id, $nonce);
    return $nonce to client;
}

verifyNonce($data, $cnonce, $hash) {
    $id = Identify Request
    $nonce = getNonce($id);  // Fetch the nonce from the last request
    removeNonce($id, $nonce); //Remove the nonce from being used again!
    $testHash = hash('sha512',$nonce . $cnonce . $data);
    return $testHash == $hash;
}

وعلى جانب العميل:

sendData($data) {
    $nonce = getNonceFromServer();
    $cnonce = hash('sha512', makeRandomString());
    $hash = hash('sha512', $nonce . $cnonce . $data);
    $args = array('data' => $data, 'cnonce' => $cnonce, 'hash' => $hash);
    sendDataToClient($args);
}

الوظيفة makeRandomString حقا يحتاج فقط إلى إرجاع رقم أو سلسلة عشوائية. كلما كان العشوائية أفضل ، كلما كان الأمان أفضل ... لاحظ أيضًا أنه نظرًا لأنه يتم تغذيته مباشرة في وظيفة التجزئة ، فإن تفاصيل التنفيذ لا تهم من الطلب إلى الطلب. لا يحتاج إصدار العميل وإصدار الخادم إلى مطابقة. في الواقع ، فإن الشيء الوحيد الذي يحتاج إلى مطابقة 100 ٪ هو وظيفة التجزئة المستخدمة في hash('sha512', $nonce . $cnonce . $data);... إليك مثال لآمنة بشكل معقول makeRandomString وظيفة...

function makeRandomString($bits = 256) {
    $bytes = ceil($bits / 8);
    $return = '';
    for ($i = 0; $i < $bytes; $i++) {
        $return .= chr(mt_rand(0, 255));
    }
    return $return;
}

نصائح أخرى

عدم القضايا هي علبة من الديدان.

لا ، حقًا ، أحد الدوافع للعديد قيصر كانت الإدخالات هي تصميم مخطط تشفير مصادق عليه ، ويفضل أن يعتمد على تشفير تيار ، وهو مقاوم لإعادة استخدام NonCe. (إعادة استخدام NonCe مع AES-CTR ، على سبيل المثال ، يدمر سرية رسالتك إلى الدرجة التي يمكن لطالب البرمجة في السنة الأولى فك تشفيرها.)

هناك ثلاث مدارس فكرية رئيسية مع غير المدارس:

  1. في تشفير المفتاح المتماثل: استخدم عدادًا متزايدًا ، مع الحرص على عدم استخدامه أبدًا. (هذا يعني أيضًا استخدام عداد منفصل للمرسل والمستقبل) 1).
  2. غير عشوائي غير دولة. توليد nonce عشوائي ثم تذكره للتحقق من صحة لاحقًا. هذه هي الاستراتيجية المستخدمة لهزيمة هجمات CSRF ، وهو ما يبدو أقرب إلى ما يطلب هنا.
  3. كبير عشوائي عديمة الجنسية. نظرًا لمولد الأرقام العشوائية الآمن ، يمكنك تقريبًا ضمان عدم تكرار NonCe مرتين في حياتك. هذه هي الاستراتيجية التي يستخدمها كلوريد الصوديوم للتشفير.

لذلك مع وضع ذلك في الاعتبار ، فإن الأسئلة الرئيسية التي يجب طرحها هي:

  1. أي من المدارس المذكورة أعلاه هي الأكثر صلة بالمشكلة التي تحاول حلها؟
  2. كيف يمكنك توليد nonce؟
  3. كيف يمكنك التحقق من صحة nonce؟

توليد nonce

الجواب على السؤال 2 عن أي غير عشوائي هو استخدام CSPRNG. بالنسبة لمشاريع PHP ، هذا يعني واحدة من:

  • random_bytes() لمشاريع PHP 7+
  • paragonie/random_compat, ، php 5 polyfill ل random_bytes()
  • ircmaxell/randomlib, ، وهي سكين في الجيش السويسري من أدوات المرافق العشوائية التي يجب أن تفكر معظم المشاريع التي تتعامل مع العشوائية (على سبيل المثال إعادة تعيين كلمة مرور FIR).

هذان الاثنان مكافئان أخلاقيا:

$factory = new RandomLib\Factory;
$generator = $factory->getMediumStrengthGenerator();
$_SESSION['nonce'] [] = $generator->generate(32);

و

$_SESSION['nonce'] []= random_bytes(32);

التحقق من صحة nonce

دولة

عدم القدامى سهلة وموصى بها:

$found = array_search($nonce, $_SESSION['nonces']);
if (!$found) {
    throw new Exception("Nonce not found! Handle this or the app crashes");
}
// Yay, now delete it.
unset($_SESSION['nonce'][$found]);

لا تتردد في استبدال array_search() مع قاعدة بيانات أو بحث memcached ، إلخ.

عديمة الجنسية (هنا تكون التنين)

هذه مشكلة صعبة في حلها: تحتاج إلى طريقة ما لمنع إعادة تشغيل هجمات ، لكن الخادم الخاص بك لديه فقدان الذاكرة الكلي بعد كل طلب HTTP.

الحل الوحيد هو مصادقة تاريخ/وقت انتهاء الصلاحية لتقليل فائدة هجمات إعادة التشغيل. فمثلا:

// Generating a message bearing a nonce
$nonce = random_bytes(32);
$expires = new DateTime('now')
    ->add(new DateInterval('PT01H'));
$message = json_encode([
    'nonce' => base64_encode($nonce),
    'expires' => $expires->format('Y-m-d\TH:i:s')
]);
$publishThis = base64_encode(
    hash_hmac('sha256', $message, $authenticationKey, true) . $message
);

// Validating a message and retrieving the nonce
$decoded = base64_decode($input);
if ($decoded === false) {
    throw new Exception("Encoding error");
}
$mac = mb_substr($decoded, 0, 32, '8bit'); // stored
$message = mb_substr($decoded, 32, null, '8bit');
$calc = hash_hmac('sha256', $message, $authenticationKey, true); // calcuated
if (!hash_equals($calc, $mac)) {
    throw new Exception("Invalid MAC");
}
$message = json_decode($message);
$currTime = new DateTime('NOW');
$expireTime = new DateTime($message->expires);
if ($currTime > $expireTime) {
    throw new Exception("Expired token");
}
$nonce = $message->nonce; // Valid (for one hour)

يلاحظ مراقب دقيق أن هذا هو في الأساس متغير غير متوافق مع المعايير رموز الويب JSON.

أحد الخيارات (التي ذكرتها في التعليق) هو تسجيل اللعب وإعادة تشغيله في بيئة آمنة.

والشيء الآخر هو أن يكون بشكل عشوائي ، أو في بعض الأوقات المحددة ، تسجيل بعض البيانات البريئة على ما يبدو ، والتي يمكن استخدامها لاحقًا للتحقق من صحة الخادم (مثل Live فجأة ، من 1 ٪ إلى 100 ٪ ، أو النتيجة من 1 إلى 1000 والتي تشير إلى الغش ). مع وجود بيانات كافية ، قد لا يكون من الممكن أن يحاول الغشاش. ثم بالطبع تنفيذ الحظر الثقيل :).

يتغير هذا غير بسيط للغاية كل 1000 ثانية (16 دقيقة) ويمكن استخدامه لتجنب XSS حيث تقوم بنشر البيانات من وإلى نفس التطبيق. (على سبيل المثال ، إذا كنت في تطبيق صفحة واحدة حيث تقوم بنشر البيانات عبر javaScript

function makeNonce($seed,$i=0){
    $timestamp = time();
    $q=-3; 
    //The epoch time stamp is truncated by $q chars, 
    //making the algorthim to change evry 1000 seconds
    //using q=-4; will give 10000 seconds= 2 hours 46 minutes usable time

    $TimeReduced=substr($timestamp,0,$q)-$i; 

    //the $seed is a constant string added to the string before hashing.    
    $string=$seed.$TimeReduced;
    $hash=hash('sha1', $string, false);
    return  $hash;
}   

ولكن من خلال التحقق من NONCE السابقة ، لن يتم إزعاج المستخدم إلا إذا انتظر أكثر من 16.6 دقيقة في أسوأ الحالات و 33 دقيقة في أفضل حالات. سيعطي تعيين $ Q = -4 المستخدم على الأقل 2.7 ساعة

function checkNonce($nonce,$seed){
//Note that the previous nonce is also checked giving  between 
// useful interval $t: 1*$qInterval < $t < 2* $qInterval where qInterval is the time deterimined by $q: 
//$q=-2: 100 seconds, $q=-3 1000 seconds, $q=-4 10000 seconds, etc.
    if($nonce==$this->makeNonce($seed,0)||$nonce==$this->makeNonce($seed,1))     {
         //handle data here
         return true;
     } else {
         //reject nonce code   
         return false;
     }
}

يمكن أن تكون البذور $ ، أي استدعاء دالة أو اسم مستخدم ، وما إلى ذلك.

لا يمكن منع الغش. يمكنك فقط جعل الأمر أكثر صعوبة.

إذا جاء شخص ما إلى هنا يبحث عن مكتبة PHP nonce: أوصي بعدم استخدام أول واحد قدمه ircmaxwell.

يصف التعليق الأول على موقع الويب عيبًا في التصميم:

إن nonce مفيد لنافذة زمنية معينة ، أي أنه كلما وصل المستخدم إلى نهاية تلك النوافذ ، كلما أقل من الوقت الذي يتعين عليه تقديمه للنموذج ، ربما أقل من ثانية واحدة

إذا كنت تبحث عن وسيلة لتوليد غير محددات مع حياة محددة جيدًا ، فأراقب nonceUtil-php.

إخلاء المسئولية: أنا مؤلف كتاب NonceUtil-PHP

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top