سؤال

يستخدم تطبيق الويب الخاص بي جلسات لتخزين المعلومات حول المستخدم بمجرد تسجيل الدخول ، والحفاظ على تلك المعلومات أثناء سفرهم من صفحة إلى أخرى داخل التطبيق. في هذا التطبيق المحدد ، أقوم بتخزين user_id, first_name و last_name الشخص.

أرغب في تقديم خيار "Keep Me Logged In" عند تسجيل الدخول الذي سيضع ملف تعريف ارتباط على جهاز المستخدم لمدة أسبوعين ، سيؤدي ذلك إلى إعادة تشغيل جلستهم بنفس التفاصيل عندما يعودون إلى التطبيق.

ما هو أفضل طريقة للقيام بذلك؟ لا أريد تخزينهم user_id في ملف تعريف الارتباط ، كما يبدو أن هذا من شأنه أن يسهل على أحد المستخدمين محاولة صياغة هوية مستخدم آخر.

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

المحلول

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

هناك. لقد قلتها. الآن يمكننا الانتقال إلى الإجابة الفعلية.

ما الخطأ في تجزئة بيانات المستخدم ، تسأل؟ حسنًا ، يتعلق الأمر بسطح التعرض والأمان من خلال الغموض.

تخيل لثانية أنك مهاجم. ترى ملف تعريف الارتباط التشفير مجموعة للتذكر في جلستك. يبلغ عرضها 32 حرفًا. جي. قد يكون هذا MD5 ...

دعونا نتخيل أيضًا لثانية أنهم يعرفون الخوارزمية التي استخدمتها. فمثلا:

md5(salt+username+ip+salt)

الآن ، كل ما يتعين على المهاجم القيام به هو إجبار "الملح" على "الملح" (وهو ليس ملحًا حقًا ، ولكن أكثر من ذلك لاحقًا) ، ويمكنه الآن توليد جميع الرموز المزيفة التي يريدها مع أي اسم مستخدم لعنوان IP الخاص به! لكن الغاشمة في الملح صعب ، أليس كذلك؟ قطعاً. لكن وحدات معالجة الرسومات في العصر الحديث جيد للغاية في ذلك. وما لم تكن تستخدم العشوائية الكافية فيه (اجعلها كبيرة بما يكفي) ، فسوف تسقط بسرعة ، ومع ذلك مفاتيح قلعتك.

باختصار ، الشيء الوحيد الذي يحميك هو الملح ، الذي لا يحميك حقًا بقدر ما تعتقد.

لكن انتظر!

كل ذلك كان يعتمد على أن المهاجم يعرف الخوارزمية! إذا كان سريًا ومربكًا ، فأنت آمن ، أليس كذلك؟ خاطئ - ظلم - يظلم. هذا الخط من التفكير له اسم: الأمن من خلال الغموض, ، التي ينبغي أبداً تعتمد عليها.

أفضل طريقة

الطريقة الأفضل هي عدم ترك معلومات المستخدم تغادر الخادم ، باستثناء المعرف.

عندما يقوم المستخدم بتسجيل الدخول ، قم بإنشاء رمز عشوائي كبير (128 إلى 256 بت). أضف ذلك إلى جدول قاعدة البيانات الذي يرسم الرمز المميز إلى معرف المستخدم ، ثم أرسله إلى العميل في ملف تعريف الارتباط.

ماذا لو كان المهاجم يخمن الرمز العشوائي لمستخدم آخر؟

حسنًا ، دعنا نفعل بعض الرياضيات هنا. نحن نولد رمز عشوائي 128 بت. هذا يعني أن هناك:

possibilities = 2^128
possibilities = 3.4 * 10^38

الآن ، لإظهار مدى سخافة هذا الرقم ، دعنا نتخيل كل خادم على الإنترنت (دعنا نقول 50،000،000 اليوم) في محاولة للوقوع في قوت هذا الرقم بمعدل 1،000،000،000 في الثانية لكل منهما. في الواقع ، ستذوب خوادمك تحت هذا الحمل ، ولكن دعونا نلعب هذا.

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 Quadrillion تخمين في الثانية. هذا هو سريع! حق؟

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 sextillions ثانية ...

دعونا نحاول نقل ذلك إلى أرقام أكثر ودية.

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() ليس قويا تقريبا بما فيه الكفاية. استخدم مكتبة ، مثل عشوائي أو Random_compat, ، أو mcrypt_create_iv() مع DEV_URANDOM)...

ال hash_equals() هو منع هجمات التوقيت. إذا كنت تستخدم إصدار PHP أدناه PHP 5.6 الوظيفة hash_equals() غير مدعومة. في هذه الحالة يمكنك استبدالها hash_equals() مع وظيفة timingsafecompare:

/**
 * 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;
}

نصائح أخرى

إشعار الأمن: يعد إنشاء ملف تعريف الارتباط من تجزئة MD5 للبيانات الحتمية فكرة سيئة ؛ من الأفضل استخدام رمز عشوائي مشتق من CSPRNG. نرى إجابة ircmaxell لهذا السؤال لنهج أكثر أمانًا.

عادة ما أفعل شيئًا كهذا:

  1. يقوم المستخدم بتسجيل الدخول باستخدام "Keep Me Logned In"
  2. إنشاء جلسة
  3. قم بإنشاء ملف تعريف ارتباط يسمى شيئًا يحتوي على: MD5 (Salt+اسم المستخدم+IP+Salt) وملف تعريف ارتباط يسمى TameElse يحتوي على معرف
  4. تخزين ملفات تعريف الارتباط في قاعدة البيانات
  5. المستخدم يفعل الأشياء والأوراق ----
  6. إرجاع المستخدم ، والتحقق من وجود ملف تعريف ارتباط شيء ، إذا كان موجودًا ، احصل على التجزئة القديمة من قاعدة البيانات لهذا المستخدم ، والتحقق من محتويات ملف تعريف الارتباط مع التجزئة من قاعدة البيانات ، والتي يجب أن تتطابق أيضًا مع تجزئة محسوبة حديثًا (من أجل IP) وهكذا: cookiehash == databasehash == MD5 (Salt+اسم المستخدم+IP+Salt) ، إذا فعلوا ذلك ، Goto 2 ، إذا لم يسبق لهم الحصول على 1

خارج الدورة التدريبية ، يمكنك استخدام أسماء ملفات تعريف الارتباط المختلفة وما إلى ذلك. يمكنك أيضًا تغيير محتوى ملف تعريف الارتباط قليلاً ، فقط تأكد من أنه ليس من السهل إنشائه. يمكنك أيضًا إنشاء user_salt user_salt عند إنشاء المستخدم وأيضًا وضعه في ملف تعريف الارتباط.

كما يمكنك استخدام SHA1 بدلاً من MD5 (أو إلى حد كبير أي خوارزمية)

مقدمة

لقبك "اجعلني مسجلاً" - أفضل طريقة اجعل من الصعب علي معرفة من أين أبدأ لأنه إذا كنت تبحث عن أفضل نهج ، فسيتعين عليك النظر في ما يلي:

  • هوية
  • حماية

بسكويت

ملفات تعريف الارتباط عرضة للخطر ، بين نقاط الضعف الشائعة للمستعرضات في المتصفح وهجمات البرمجة النصية عبر المواقع ، يجب أن نقبل أن ملفات تعريف الارتباط ليست آمنة. للمساعدة في تحسين الأمان ، يجب ملاحظة ذلك php setcookies له وظائف إضافية مثل

بول setcookie (Name $ $ [، string $ value [، int $ Expire = 0 [، String $ path [، String $ Domain [، Bool آمنة $ = خطأ [، منطقي $ httponly = خطأ]]]]]]]])

  • آمنة (باستخدام اتصال HTTPS)
  • httponly (قلل من سرقة الهوية من خلال هجوم XSS)

تعريفات

  • الرمز المميز (سلسلة عشوائية لا يمكن التنبؤ بها من الطول n على سبيل المثال /dev /urandom)
  • مرجع (سلسلة عشوائية لا يمكن التنبؤ بها من الطول n على سبيل المثال /dev /urandom)
  • توقيع (قم بإنشاء قيمة تجزئة مفتاح باستخدام طريقة HMAC)

نهج بسيط

سيكون الحل البسيط:

  • تم تسجيل الدخول إلى المستخدم مع تذكرني
  • ملف تعريف الارتباط تسجيل الدخول الصادر مع الرمز المميز والتوقيع
  • متى يعود ، يتم فحص التوقيع
  • إذا كان التوقيع على ما يرام .. ثم يتم النظر إلى اسم المستخدم والرمز في قاعدة البيانات
  • إذا لم يكن صالحًا .. عد إلى صفحة تسجيل الدخول
  • إذا كان صالحًا لتسجيل الدخول تلقائيًا

تلخص دراسة الحالة أعلاه كل المثال الوارد في هذه الصفحة ولكنها عيوب هي ذلك

  • لا توجد طريقة لمعرفة ما إذا كانت ملفات تعريف الارتباط سُرقت
  • قد يكون المهاجم هو الوصول إلى عمليات حساسة مثل تغيير كلمة المرور أو البيانات مثل المعلومات الشخصية والخبز وما إلى ذلك.
  • سيظل ملف تعريف الارتباط المعرض للخطر صالحًا لمدى الحياة

حل أفضل

سيكون حل أفضل

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

رمز مثال

// Set privateKey
// This should be saved securely 
$key = 'fc4d57ed55a78de1a7b31e711866ef5a2848442349f52cd470008f6d30d47282';
$key = pack("H*", $key); // They key is used in binary form

// Am Using Memecahe as Sample Database
$db = new Memcache();
$db->addserver("127.0.0.1");

try {
    // Start Remember Me
    $rememberMe = new RememberMe($key);
    $rememberMe->setDB($db); // set example database

    // Check if remember me is present
    if ($data = $rememberMe->auth()) {
        printf("Returning User %s\n", $data['user']);

        // Limit Acces Level
        // Disable Change of password and private information etc

    } else {
        // Sample user
        $user = "baba";

        // Do normal login
        $rememberMe->remember($user);
        printf("New Account %s\n", $user);
    }
} catch (Exception $e) {
    printf("#Error  %s\n", $e->getMessage());
}

الفئة المستخدمة

class RememberMe {
    private $key = null;
    private $db;

    function __construct($privatekey) {
        $this->key = $privatekey;
    }

    public function setDB($db) {
        $this->db = $db;
    }

    public function auth() {

        // Check if remeber me cookie is present
        if (! isset($_COOKIE["auto"]) || empty($_COOKIE["auto"])) {
            return false;
        }

        // Decode cookie value
        if (! $cookie = @json_decode($_COOKIE["auto"], true)) {
            return false;
        }

        // Check all parameters
        if (! (isset($cookie['user']) || isset($cookie['token']) || isset($cookie['signature']))) {
            return false;
        }

        $var = $cookie['user'] . $cookie['token'];

        // Check Signature
        if (! $this->verify($var, $cookie['signature'])) {
            throw new Exception("Cokies has been tampared with");
        }

        // Check Database
        $info = $this->db->get($cookie['user']);
        if (! $info) {
            return false; // User must have deleted accout
        }

        // Check User Data
        if (! $info = json_decode($info, true)) {
            throw new Exception("User Data corrupted");
        }

        // Verify Token
        if ($info['token'] !== $cookie['token']) {
            throw new Exception("System Hijacked or User use another browser");
        }

        /**
         * Important
         * To make sure the cookie is always change
         * reset the Token information
         */

        $this->remember($info['user']);
        return $info;
    }

    public function remember($user) {
        $cookie = [
                "user" => $user,
                "token" => $this->getRand(64),
                "signature" => null
        ];
        $cookie['signature'] = $this->hash($cookie['user'] . $cookie['token']);
        $encoded = json_encode($cookie);

        // Add User to database
        $this->db->set($user, $encoded);

        /**
         * Set Cookies
         * In production enviroment Use
         * setcookie("auto", $encoded, time() + $expiration, "/~root/",
         * "example.com", 1, 1);
         */
        setcookie("auto", $encoded); // Sample
    }

    public function verify($data, $hash) {
        $rand = substr($hash, 0, 4);
        return $this->hash($data, $rand) === $hash;
    }

    private function hash($value, $rand = null) {
        $rand = $rand === null ? $this->getRand(4) : $rand;
        return $rand . bin2hex(hash_hmac('sha256', $value . $rand, $this->key, true));
    }

    private function getRand($length) {
        switch (true) {
            case function_exists("mcrypt_create_iv") :
                $r = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
                break;
            case function_exists("openssl_random_pseudo_bytes") :
                $r = openssl_random_pseudo_bytes($length);
                break;
            case is_readable('/dev/urandom') : // deceze
                $r = file_get_contents('/dev/urandom', false, null, 0, $length);
                break;
            default :
                $i = 0;
                $r = "";
                while($i ++ < $length) {
                    $r .= chr(mt_rand(0, 255));
                }
                break;
        }
        return substr(bin2hex($r), 0, $length);
    }
}

اختبار في Firefox و Chrome

enter image description here

ميزة

  • أمن أفضل
  • وصول محدود للمهاجم
  • عندما يتم سرقة ملف تعريف الارتباط ، فإنه صالح فقط للوصول الفردي
  • عندما يصل المستخدم الأصلي إلى الموقع ، يمكنك اكتشاف المستخدم وإخطاره تلقائيًا بالسرقة

عيب

  • لا يدعم الاتصال المستمر عبر متصفح متعدد (الهاتف المحمول والويب)
  • لا يزال من الممكن سرقة ملف تعريف الارتباط لأن المستخدم يحصل فقط على الإشعار بعد تسجيل الدخول التالي.

إصلاح سريع

  • إدخال نظام الموافقة لكل نظام يجب أن يكون له اتصال مستمر
  • استخدم ملفات تعريف الارتباط المتعددة للمصادقة

نهج ملفات تعريف الارتباط المتعددة

عندما يكون المهاجم على وشك سرقة ملفات تعريف الارتباط ، فإن التركيز الوحيد على موقع ويب أو مجال معين على سبيل المثال. example.com

ولكن في الحقيقة يمكنك مصادقة مستخدم من نطفين مختلفين (example.com & fakeaddsite.com) وجعلها تبدو وكأنها "إعلان ملف تعريف الارتباط"

  • قام المستخدم بتسجيل الدخول إلى example.com مع تذكرني
  • تخزين اسم المستخدم ، الرمز المميز ، مرجع في ملف تعريف الارتباط
  • تخزين اسم المستخدم ، الرمز المميز ، المرجع في قاعدة البيانات على سبيل المثال. memcache
  • إرسال معرف الامتناع عبر GET و IFRAME إلى fakeaddsite.com
  • يستخدم fakeaddsite.com المرجع إلى جلب المستخدم والرمز من قاعدة البيانات
  • يقوم Fakeaddsite.com بتخزين التوقيع
  • عندما يقوم المستخدم بإرجاع معلومات توقيع الجلب مع iframe من fakeaddsite.com
  • الجمع بين بيانات تكنولوجيا المعلومات والقيام بالتحقق من الصحة
  • ..... أنت تعرف المتبقية

قد يتساءل بعض الناس كيف يمكنك استخدام اثنين من ملفات تعريف الارتباط المختلفة؟ حسنًا ، إنه ممكن ، تخيل example.com = localhost و fakeaddsite.com = 192.168.1.120. إذا قمت بفحص ملفات تعريف الارتباط ، فستبدو هكذا

enter image description here

من الصورة أعلاه

  • الموقع الحالي الذي تمت زيارته هو مضيف محلي
  • كما أنه يحتوي على ملفات تعريف الارتباط المحددة من 192.168.1.120

192.168.1.120

  • يقبل فقط المحددة HTTP_REFERER
  • يقبل الاتصال فقط من المحدد REMOTE_ADDR
  • لا javaScript ، لا محتوى ولكن لا يتكون شيئًا بدلاً من توقيع المعلومات وإضافة أو استردادها من ملف تعريف الارتباط

ميزة

  • 99 ٪ من الوقت الذي خدعت فيه المهاجم
  • يمكنك بسهولة قفل الحساب في المحاولة الأولى للمهاجم
  • يمكن منع الهجوم حتى قبل تسجيل الدخول التالي مثل الطرق الأخرى

عيب

  • طلب متعدد إلى الخادم فقط لتسجيل دخول واحد

تحسين

  • القيام باستخدام iframe استخدام ajax

هناك مقالان مثيران للاهتمام للغاية ، لقد وجدت أثناء البحث عن حل مثالي لـ "remergen-me" -prombled:

سألت زاوية واحدة من هذا السؤال هنا, ، وستقودك الإجابات إلى جميع روابط ملفات تعريف الارتباط التي تحتاجها الرمز المميز الذي تحتاجه.

في الأساس ، لا تقوم بتخزين معرف المستخدم في ملف تعريف الارتباط. يمكنك تخزين رمز رمزي لمرة واحدة (سلسلة ضخمة) يستخدمه المستخدم لالتقاط جلسة تسجيل الدخول القديمة. ثم لجعلها آمنة حقًا ، تطلب كلمة مرور للعمليات الثقيلة (مثل تغيير كلمة المرور نفسها).

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

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

الموضوع القديم ، ولكن لا يزال مصدر قلق صحيح. لقد لاحظت بعض الاستجابات الجيدة حول الأمن ، وتجنب استخدام "الأمن من خلال الغموض" ، لكن الأساليب التقنية الفعلية المقدمة لم تكن كافية في عيني. أشياء يجب أن أقولها قبل أن أساهم في طريقتي:

  • أبداً تخزين كلمة مرور في نص واضح ... من أي وقت مضى!
  • أبداً قم بتخزين كلمة مرور تجزئة المستخدم في أكثر من موقع واحد في قاعدة البيانات الخاصة بك. إن الواجهة الخلفية للخادم الخاصة بك قادر دائمًا على سحب كلمة مرور التجزئة من جدول المستخدمين. ليس أكثر كفاءة تخزين بيانات زائدة عن الحاجة بدلاً من معاملات DB إضافية ، والعكس صحيح.
  • يجب أن يكون معرف الجلسة الخاص بك فريدًا ، لذلك لا يمكن لأي مستخدمين أي وقت مضى شارك معرفًا ، وبالتالي الغرض من معرف (هل يمكن أن يتطابق رقم معرف رخصة قيادتك على أشخاص آخرون؟ يجب أن يستخدم جدول الجلسات الخاص بك المعرف باعتباره PK. للسماح للثقة بأجهزة متعددة في Signinin التلقائي ، استخدم جدولًا آخر للأجهزة الموثوقة التي تحتوي على قائمة جميع الأجهزة التي تم التحقق منها (انظر المثال الخاص بي أدناه) ، ويتم تعيينه باستخدام اسم المستخدم.
  • لا يخدم أي غرض من تجزئة البيانات المعروفة في ملف تعريف الارتباط ، ويمكن نسخ ملف تعريف الارتباط. ما نبحث عنه هو جهاز مستخدم متماسك لتوفير معلومات أصلية لا يمكن الحصول عليها بدون مهاجم يمسح جهاز المستخدم (مرة أخرى ، انظر مثالي). ومع ذلك ، فإن هذا قد يعني أن المستخدم الشرعي الذي يحظر المعلومات الثابتة لجهازه (أي عنوان MAC ، اسم مضيف الجهاز ، useragent إذا كان مقيدًا بواسطة المتصفح ، إلخ) من البقاء ثابتًا (أو محاكاة محاكاة في المقام الأول) لن يتمكن من ذلك استخدم هذه الميزة. ولكن إذا كان هذا مصدر قلق ، ففكر في حقيقة أنك تقدم signin تلقائي للمستخدمين الذين تعريف أنفسهم بشكل فريد, ، لذلك إذا رفضوا أن يعرفوا عن طريق خداع MAC الخاص بهم ، وتخزين مستخدميهم ، أو خداع/تغيير اسم المضيف الخاص بهم ، والاختباء خلف الوكلاء ، وما إلى ذلك ، فهي لا يمكن التعرف عليها ، ويجب ألا يتم مصادقةها أبدًا لخدمة تلقائية. إذا كنت تريد ذلك ، فأنت بحاجة إلى النظر في الوصول إلى بطاقة ذكية مجمعة مع برامج من جانب العميل والتي تنشئ هوية للجهاز المستخدم.

هذا كل ما يقال ، هناك طريقتان رائعتان للحصول على signin التلقائي على نظامك.

أولاً ، الطريقة الرخيصة والسهلة التي تضع كل شيء على شخص آخر. إذا قمت بعمل دعم لموقعك ، على سبيل المثال ، حساب Google+ الخاص بك ، فمن المحتمل أن يكون لديك زر Google+ مبسط يقوم بتسجيل المستخدم إذا تم تسجيله بالفعل في Google (لقد فعلت ذلك هنا للإجابة على هذا السؤال ، كما أنا دائمًا وقعت على جوجل). إذا كنت ترغب في تسجيل الدخول تلقائيًا إذا تم تسجيل الدخول بالفعل مع مصادقة موثوقة ودعم ، وفحص المربع للقيام بذلك ، اجعل البرامج النصية من جانب العميل تنفذ الرمز خلف الزر "تسجيل الدخول" المقابل قبل التحميل ، فقط تأكد من وجود معرف خادم معرف فريد في جدول SIGNIN التلقائي يحتوي على اسم المستخدم ومعرف الجلسة والمصادقة المستخدمة للمستخدم. نظرًا لأن طرق تسجيل الدخول هذه تستخدم AJAX ، فأنت تنتظر استجابة على أي حال ، وهذه الاستجابة هي إما استجابة تم التحقق منها أو رفض. إذا حصلت على استجابة تم التحقق من صحتها ، فاستخدمها كالمعتاد ، فاستمر في تحميل المستخدم المسجل على أنه عادي. خلاف ذلك ، فشل تسجيل الدخول ، لكن لا تخبر المستخدم ، فقط لا تتم دون تسجيل الدخول ، سوف يلاحظون ذلك. هذا هو منع المهاجم الذي سرق ملفات تعريف الارتباط (أو قام بتزويرها في محاولة لتصاعد الامتيازات) من تعلم أن المستخدم تلقائيًا في الموقع.

هذا رخيص ، وقد يعتبره البعض متسخًا أيضًا لأنه يحاول التحقق من صحة محتمل بالفعل في الذات مع أماكن مثل Google و Facebook ، حتى دون إخبارك. ومع ذلك ، لا ينبغي استخدامه على المستخدمين الذين لم يطلبوا من socizing signin موقعك ، وهذه الطريقة بالذات مخصصة فقط للمصادقة الخارجية ، كما هو الحال مع Google+ أو FB.

نظرًا لأنه تم استخدام مصادقة خارجي لإخبار الخادم وراء الكواليس ما إذا كان قد تم التحقق من صحة المستخدم أم لا ، لا يمكن للمهاجم الحصول على أي شيء آخر غير معرف فريد ، وهو أمر غير مجدي من تلقاء نفسه. سأشرح:

  • يزور المستخدم موقع "جو" لأول مرة ، معرف الجلسة الموضوعة في جلسة ملف تعريف الارتباط.
  • يقوم المستخدم "Joe" بتسجيل الدخول ، وتصاعد الامتيازات ، ويحصل على معرف جلسة جديد ويجدد ملف تعريف الارتباط ".
  • ينتخب المستخدم "Joe" لـ Auto-Signin باستخدام Google+، ويحصل على معرف فريد من نوعه في ملف تعريف الارتباط "KeepMesignedIn".
  • قام المستخدم "Joe" بإبقاء Google موقّعًا لهم ، مما يسمح لموقعك بتجديد المستخدم التلقائي باستخدام Google في الواجهة الخلفية الخاصة بك.
  • يحاول المهاجم بشكل منهجي معرفات فريدة من نوعها لـ "KeepMesignedIn" (هذه هي المعرفة العامة التي يتم توزيعها على كل مستخدم) ، ولا يتم تسجيلها في أي مكان آخر ؛ يحاول معرف فريد من نوعه إلى "جو".
  • يتلقى الخادم معرفًا فريدًا لـ "Joe" ، ويسحب المطابقة في DB لحساب Google+.
  • يرسل الخادم المهاجم إلى صفحة تسجيل الدخول التي تقوم بتشغيل طلب AJAX إلى Google لتسجيل الدخول.
  • يتلقى Google Server طلبًا ، ويستخدم واجهة برمجة التطبيقات الخاصة به لرؤية المهاجم لا يتم تسجيل الدخول حاليًا.
  • يرسل Google استجابة أنه لا يوجد موقّع حاليًا في المستخدم على هذا الاتصال.
  • تتلقى صفحة المهاجم استجابة ، ويعيد البرنامج النصي تلقائيًا إلى صفحة تسجيل الدخول مع قيمة ما بعد ترميزها في عنوان URL.
  • تحصل صفحة تسجيل الدخول على قيمة المنشور ، وترسل ملف تعريف الارتباط لـ "KeepMesignedIn" إلى قيمة فارغة وصالحة حتى تاريخ 1-1-1970 لردع محاولة تلقائية ، مما تسبب في حذف مستعرض المهاجم ببساطة.
  • يتم إعطاء المهاجم صفحة تسجيل الدخول العادية لأول مرة.

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

يمكن وينبغي استخدام هذه الطريقة بالاقتران مع المصادقة الداخلية الخاصة بك لأولئك الذين يقومون بتسجيل الدخول إلى موقعك باستخدام مصادقة خارجي.

=========

الآن ، لنظام المصادقة الخاص بك والذي يمكنه مستخدمي signin تلقائيًا ، هكذا أفعل ذلك:

يحتوي DB على عدد قليل من الجداول:

TABLE users:
UID - auto increment, PK
username - varchar(255), unique, indexed, NOT NULL
password_hash - varchar(255), NOT NULL
...

لاحظ أن اسم المستخدم قادر على طول 255 حرفًا. لديّ برنامج خادم الخاص بي يحد من أسماء المستخدمين في نظامي إلى 32 حرفًا ، ولكن قد يكون للمصادقين الخارجيين أسماء مستخدمة مع @domain.tld تكون أكبر من ذلك ، لذلك أنا فقط أؤيد الطول الأقصى لعنوان البريد الإلكتروني لأقصى قدر من التوافق.

TABLE sessions:
session_id - varchar(?), PK
session_token - varchar(?), NOT NULL
session_data - MediumText, NOT NULL

لاحظ أنه لا يوجد حقل مستخدم في هذا الجدول ، لأن اسم المستخدم ، عند تسجيل الدخول ، موجود في بيانات الجلسة ، ولا يسمح البرنامج بالبيانات الخالية. يمكن إنشاء Session_id و Session_token باستخدام تجزئة MD5 العشوائية ، SHA1/128/256 ، طوابع داترام مع سلاسل عشوائية تمت إضافتها إليهم ثم تجزئة ، أو ما تريد ، ولكن يجب أن يظل إنتروبيا من إخراجك مرتفعًا على مقبولة تخفيف هجمات القوة الغاشمة من النزول من الأرض ، ويجب فحص جميع التجزئة التي تم إنشاؤها بواسطة فئة الجلسة الخاصة بك للمباريات في جدول الجلسات قبل محاولة إضافتها.

TABLE autologin:
UID - auto increment, PK
username - varchar(255), NOT NULL, allow duplicates
hostname - varchar(255), NOT NULL, allow duplicates
mac_address - char(23), NOT NULL, unique
token - varchar(?), NOT NULL, allow duplicates
expires - datetime code

من المفترض أن تكون عناوين MAC بطبيعتها فريدة من نوعها ، وبالتالي فمن المنطقي أن يكون لكل إدخال قيمة فريدة. أسماء المضيف ، من ناحية أخرى ، يمكن تكرارها على شبكات منفصلة بشكل شرعي. كم عدد الأشخاص الذين يستخدمون "Home-PC" كأحد أسماء أجهزة الكمبيوتر الخاصة بهم؟ اسم المستخدم مأخوذ من بيانات الجلسة بواسطة الواجهة الخلفية للخادم ، لذلك من المستحيل معالجة ذلك. أما بالنسبة للرمز المميز ، فيجب استخدام نفس الطريقة لإنشاء رموز جلسة للصفحات لإنشاء الرموز الرموز في ملفات تعريف الارتباط الخاصة بـ User Auto-Signin. أخيرًا ، تتم إضافة رمز DateTime لموعد يحتاج المستخدم إلى إعادة صياغة بيانات اعتماده. إما تحديث وقت البيانات هذا على تسجيل الدخول إلى المستخدم الذي يحتفظ به في غضون بضعة أيام ، أو إجباره على انتهاء صلاحيته بغض النظر عن آخر تسجيل دخول للحفاظ عليه لمدة شهر أو نحو ذلك ، أيهما يملي التصميم الخاص بك.

هذا يمنع شخص ما من تخوينت بشكل منهجي جهاز Mac واسم المضيف للمستخدم الذي يعرفه في التوقيع التلقائي. أبداً اطلب من المستخدم الاحتفاظ بملف تعريف الارتباط مع كلمة المرور الخاصة به ، أو نص واضح أو غير ذلك. اطلب من ذلك إعادة تنظيم الرمز المميز في كل صفحة من التنقل ، تمامًا كما تفعل رمز الجلسة. هذا يقلل بشكل كبير من احتمال أن يتمكن المهاجم من الحصول على ملف تعريف ارتباط رمزي صالح واستخدامه لتسجيل الدخول. سيحاول بعض الأشخاص أن يقولوا إن المهاجم يمكنه سرقة ملفات تعريف الارتباط من الضحية والقيام بهجوم إعادة تشغيل الجلسة لتسجيل الدخول. إذا تمكن المهاجم من سرقة ملفات تعريف الارتباط (وهو أمر ممكن) ، فمن المؤكد أنه كان سيضعف الجهاز بأكمله ، مما يعني أنه يمكنهم فقط استخدام الجهاز لتسجيل الدخول على أي حال ، مما يهزم غرض سرقة ملفات تعريف الارتباط بالكامل. طالما أن موقعك يعمل فوق HTTPS (والذي ينبغي عليه التعامل مع كلمات المرور أو أرقام CC أو غيرها من أنظمة تسجيل الدخول) ، فقد منحت كل الحماية للمستخدم التي يمكنك داخل المتصفح.

شيء واحد يجب وضعه في الاعتبار: يجب ألا تنتهي بيانات الجلسة إذا كنت تستخدم SIGNIN التلقائي. يمكنك انتهاء صلاحية القدرة على متابعة الجلسة بشكل خاطئ ، ولكن يجب أن تستأنف التحقق من صحة النظام بيانات الجلسة إذا كانت بيانات مستمرة من المتوقع أن تستمر بين الجلسات. إذا كنت تريد كل من بيانات الجلسة المستمرة وغير المتسقة ، فاستخدم جدولًا آخر لبيانات الجلسة المستمرة مع اسم المستخدم كـ PK ، وجعل الخادم يسترجعها كما لو كانت بيانات الجلسة العادية ، ما عليك سوى استخدام متغير آخر.

بمجرد تحقيق تسجيل الدخول بهذه الطريقة ، لا يزال يتعين على الخادم التحقق من صحة الجلسة. هذا هو المكان الذي يمكنك فيه ترميز توقعات الأنظمة المسروقة أو المعرضة للخطر ؛ غالبًا ما تؤدي الأنماط والنتائج الأخرى المتوقعة لتسجيل الدخول إلى بيانات الجلسة إلى استنتاجات مفادها أن النظام تم اختطافه أو مزورة ملفات تعريف الارتباط من أجل الوصول. هذا هو المكان الذي يمكن أن تضع فيه تقنية ISS الخاصة بك القواعد التي من شأنها أن تؤدي إلى تأمين حساب أو إعادة إدخال تلقائي للمستخدم من نظام signin التلقائي ، مما يجعل المهاجمين خارجًا بدرجة كافية للمستخدم لتحديد كيفية نجاح المهاجم وكيفية قطعهم.

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

أعتذر إذا كان أي شخص يتوقع أن يتم تقديم رمز في إجابتي ، فلن يحدث هذا هنا. سأقول إنني أستخدم PHP و JQuery و Ajax لتشغيل مواقعي ، وأنا لا أستخدم Windows أبدًا كخادم ... على الإطلاق.

الحل الخاص بي مثل هذا. إنها ليست مقاومة للرصاص بنسبة 100 ٪ ، لكنني أعتقد أنها ستوفر لك معظم الحالات.

عندما قام المستخدم بتسجيل الدخول بنجاح ، قم بإنشاء سلسلة مع هذه المعلومات:

$data = (SALT + ":" + hash(User Agent) + ":" + username 
                     + ":" + LoginTimestamp + ":"+ SALT)

تشفير $data, ، اضبط النوع على httponly وضبط ملف تعريف الارتباط.

عندما يعود المستخدم إلى موقعك ، اتخذ هذه الخطوات:

  1. احصل على بيانات ملفات تعريف الارتباط. إزالة الأحرف الخطرة داخل ملف تعريف الارتباط. تنفجر مع : حرف.
  2. تحقق من الصلاحية. إذا كان ملف تعريف الارتباط أقدم من X أيام ، فقم بإعادة توجيه المستخدم إلى صفحة تسجيل الدخول.
  3. إذا لم يكن ملف تعريف الارتباط قديمًا ؛ احصل على أحدث وقت تغيير كلمة المرور من قاعدة البيانات. إذا تم تغيير كلمة المرور بعد آخر تسجيل دخول للمستخدم إلى صفحة تسجيل الدخول إلى صفحة تسجيل الدخول.
  4. إذا لم يتغير المرور مؤخرًا ؛ احصل على وكيل المتصفح الحالي للمستخدم. تحقق مما إذا كان (CurrentUseragenthash == CookieUseragenthash). إذا كانت الوكلاء هي نفسها ، فانتقل إلى الخطوة التالية ، وإعادة التوجيه إلى صفحة تسجيل الدخول.
  5. إذا نجحت جميع الخطوات التي تم إجراؤها على اسم المستخدم بنجاح.

إذا توقيع المستخدم ، قم بإزالة ملف تعريف الارتباط هذا. قم بإنشاء ملف تعريف ارتباط جديد إذا أعيد استخدام المستخدم.

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

أفكر في اتباع هذا النهج إلى "تذكرني". إذا كنت تستطيع رؤية أي مشكلات ، يرجى التعليق.

  1. قم بإنشاء جدول لتخزين بيانات "تذكرني" - منفصل عن جدول المستخدم حتى أتمكن من تسجيل الدخول من أجهزة متعددة.

  2. على تسجيل الدخول الناجح (مع تذكرني):

    أ) إنشاء سلسلة عشوائية فريدة لاستخدامها كمستخدم المستخدم على هذا الجهاز: BigUserId

    ب) إنشاء سلسلة عشوائية فريدة: BigKey

    ج) تخزين ملف تعريف الارتباط: Biguserid: BigKey

    د) في جدول "تذكرني" ، أضف سجلًا مع: userId ، عنوان IP ، BigUserid ، BigKey

  3. إذا حاولت الوصول إلى شيء يتطلب تسجيل الدخول:

    أ) تحقق من ملف تعريف الارتباط وابحث عن BigUserid & Bigkey مع عنوان IP مطابق

    ب) إذا وجدت ذلك ، فقم بتسجيل الشخص ولكن قم بتعيين علامة في جدول المستخدم "تسجيل الدخول الناعم" بحيث يمكنك المطالبة بتسجيل الدخول الكامل لأي عمليات خطيرة.

  4. في تسجيل الخروج ، حدد جميع سجلات "تذكرني" لهذا المستخدم كما انتهت صلاحيتها.

نقاط الضعف الوحيدة التي يمكنني رؤيتها هي ؛

  • يمكنك الحصول على كمبيوتر محمول لشخص ما وتخفيف عنوان IP الخاص به باستخدام ملف تعريف الارتباط.
  • يمكنك أن تكون محادثة عنوان IP مختلف في كل مرة وتخمين الأمر برمته - ولكن مع سلسلة كبيرة لتتناسب مع ذلك ، سيكون ذلك ... القيام بحساب مماثل إلى أعلاه ... ليس لدي أي فكرة ... احتمالات هائلة؟

قرأت جميع الإجابات وما زلت وجدت صعوبة في استخراج ما كان من المفترض أن أفعله. إذا كانت الصورة تستحق كلمات واحدة كيلومتر ، آمل أن يساعد ذلك الآخرين في تنفيذ سعة تخزين مستمرة آمنة استنادًا إلى Barry Jaspan's تحسين أفضل الممارسات لتسجيل الدخول إلى تسجيل الدخول

enter image description here

إذا كانت لديك أسئلة أو ملاحظات أو اقتراحات ، فسأحاول تحديث المخطط للانعكاس للمبتدئ الذي يحاول تنفيذ تسجيل دخول مستمر آمن.

يعني تنفيذ ميزة "Keep Me Docted In" أنك تحتاج إلى تحديد ما يعنيه ذلك بالضبط للمستخدم. في أبسط الحالات ، أود استخدام ذلك ليعني أن الجلسة لها مهلة أطول بكثير: يومين (على سبيل المثال) بدلاً من ساعتين. للقيام بذلك ، ستحتاج إلى تخزين الجلسة الخاص بك ، ربما في قاعدة بيانات ، بحيث يمكنك تعيين أوقات انتهاء صلاحية مخصصة لبيانات الجلسة. ثم تحتاج إلى التأكد من تعيين ملف تعريف الارتباط الذي سوف يتجول لبضعة أيام (أو أكثر) ، بدلاً من انتهاء صلاحيته عندما يغلقون المتصفح.

أستطيع أن أسمع أنك تسأل "لماذا يومين؟ لماذا لا أسبوعين؟". وذلك لأن استخدام جلسة في PHP سيؤدي تلقائيًا إلى دفع انتهاء الصلاحية. وذلك لأن انتهاء الجلسة في PHP هو في الواقع مهلة خاملة.

الآن ، بعد أن قلت ذلك ، من المحتمل أن أقوم بتنفيذ قيمة مهلة أصعب أقوم بتخزينها في الجلسة نفسها ، وفي أسبوعين أو نحو ذلك ، وأضف رمزًا لرؤية ذلك وإبطال الجلسة بشكل قسري. أو على الأقل لتسجيلها. هذا يعني أنه سيُطلب من المستخدم تسجيل الدخول بشكل دوري. ياهو! هل هذا.

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