المصادقة المستندة إلى نماذج PHP على نظام التشغيل Windows باستخدام حسابات المستخدمين المحليين

StackOverflow https://stackoverflow.com/questions/60585

سؤال

أقوم بتشغيل PHP وApache وWindows.ليس لدي إعداد مجال، لذا أرغب في أن تستخدم المصادقة المستندة إلى النماذج لموقع الويب الخاص بي قاعدة بيانات حسابات المستخدمين المحلية المضمنة في Windows (أعتقد أنها تسمى SAM).

أعلم أنه إذا تم إعداد Active Directory، فيمكنك استخدام وحدة PHP LDAP للاتصال والمصادقة في البرنامج النصي الخاص بك، ولكن بدون AD لا يوجد LDAP.ما هو المعادل للآلات المستقلة؟

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

المحلول

ولم أجد حلاً بسيطًا أيضًا.توجد أمثلة باستخدام CreateObject وموفر WinNT ADSI.لكن في النهاية يصطدمون جميعًا مشكلات مصادقة المستخدم مع موفر WinNT لواجهات خدمة الدليل النشط.لست متأكدًا بنسبة 100% ولكنني يخمن أسلوب الاتصال WSH/الشبكة لديه نفس المشكلة.
وفق كيفية التحقق من صحة بيانات اعتماد المستخدم على أنظمة تشغيل Microsoft يجب عليك استخدام LogonUser أو SSPI.
ويقول أيضا

LogonUser Win32 API does not require TCB privilege in Microsoft Windows Server 2003, however, for downlevel compatibility, this is still the best approach.

في نظام التشغيل Windows XP، لم يعد من الضروري أن تتمتع العملية بامتياز SE_TCB_NAME لاستدعاء LogonUser.ولذلك، فإن أبسط طريقة للتحقق من صحة بيانات اعتماد المستخدم على نظام التشغيل Windows XP، هي استدعاء LogonUser API.

لذلك، إذا كنت متأكدًا من عدم الحاجة إلى دعم Win9x/2000، فسأكتب ملحقًا يعرض LogonUser إلى php.
قد تكون مهتم ايضا ب مصادقة المستخدم من حسابات NT.فهو يستخدم ملحق w32api، ويحتاج إلى دعم dll ... أفضل أن أكتب ملحق LogonUser الصغير هذا؛-)
إذا لم يكن ذلك ممكنًا، فمن المحتمل أن ألقي نظرة على وحدة fastcgi لـ IIS ومدى استقرارها والسماح لـ IIS بالتعامل مع المصادقة.

يحرر:
لقد حاولت أيضًا الاستفادة System.Security.Principal.WindowsIdentity و PHP امتداد com/.net.ولكن يبدو أن مُنشئ dotnet لا يسمح بتمرير المعلمات إلى مُنشئ الكائنات وفشلت "تجربتي" للحصول على التجميع (ومعها CreateInstance()) من GetType() مع ظهور خطأ "zval غير معروف".

نصائح أخرى

سؤال جيد!

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

ملف SAM محظور أثناء تشغيل النظام.هناك بعض حيل حقن DLL التي قد تتمكن من العمل ولكن في النهاية سينتهي بك الأمر بتجزئة كلمة المرور وسيتعين عليك تجزئة كلمات المرور التي قدمها المستخدم لمطابقتها على أي حال.

ما تريده حقًا هو شيء يحاول مصادقة المستخدم مقابل ملف SAM.أعتقد أنه يمكنك القيام بذلك عن طريق القيام بشيء مثل ما يلي.

  1. قم بإنشاء مشاركة ملف على الخادم واجعلها بحيث يتم منح الوصول إليها فقط للحسابات التي تريد أن تكون قادرًا على تسجيل الدخول بها.
  2. في PHP، استخدم أمر النظام لاستدعاء البرنامج النصي wsh الذي:يقوم بتحميل المشاركة باستخدام اسم المستخدم وكلمة المرور التي يوفرها مستخدم موقع الويب.يسجل ما إذا كان يعمل، ثم يقوم بإلغاء تحميل محرك الأقراص إذا كان يعمل.
  3. جمع النتيجة بطريقة أو بأخرى.يمكن إرجاع النتيجة إلى PHP إما على stdout للبرنامج النصي، أو نأمل باستخدام رمز الإرجاع للبرنامج النصي.

أعلم أنها ليست جميلة، لكن يجب أن تعمل.

أشعر بالقذارة :|

يحرر:سبب استدعاء البرنامج النصي wsh الخارجي هو أن PHP لا يسمح لك باستخدام مسارات UNC (على حد ما أستطيع أن أتذكر).

يتطلب إنشاء امتداد PHP استثمارًا كبيرًا جدًا من حيث مساحة القرص الصلب.وبما أنني قمت بالفعل بتثبيت بيئة مجلس التعاون الخليجي (MinGW)، فقد قررت أن أحصل على نتيجة الأداء المتمثلة في إطلاق عملية من البرنامج النصي PHP.كود المصدر أدناه.

// Usage: logonuser.exe /user username /password password [/domain domain]
// Exit code is 0 on logon success and 1 on failure.

#include <windows.h>

int main(int argc, char *argv[]) {
    HANDLE r = 0;
    char *user = 0;
    char *password = 0;
    char *domain = 0;
    int i;

    for(i = 1; i < argc; i++) {
        if(!strcmp(argv[i], "/user")) {
            if(i + 1 < argc) {
                user = argv[i + 1];
                i++;
            }
        } else if(!strcmp(argv[i], "/domain")) {
            if(i + 1 < argc) {
                domain = argv[i + 1];
                i++;
            }
        } else if(!strcmp(argv[i], "/password")) {
            if(i + 1 < argc) {
                password = argv[i + 1];
                i++;
            }
        }
    }

    if(user && password) {
        LogonUser(user, domain, password, LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT, &r);
    }
    return r ? 0 : 1;
}

التالي هو مصدر PHP الذي يوضح استخدامه.

if($_SERVER['REQUEST_METHOD'] == 'POST') {
    if(isset($_REQUEST['user'], $_REQUEST['password'], $_REQUEST['domain'])) {
        $failure = 1;
        $user = $_REQUEST['user'];
        $password = $_REQUEST['password'];
        $domain = $_REQUEST['domain'];

        if($user && $password) {
            $cmd = "logonuser.exe /user " . escapeshellarg($user) . " /password " . escapeshellarg($password);
            if($domain) $cmd .= " /domain " . escapeshellarg($domain);
            system($cmd, $failure);
        }

        if($failure) {
            echo("Incorrect credentials.");
        } else {
            echo("Correct credentials!");
        }
    }
}
?>
<form action="<?php echo(htmlentities($_SERVER['PHP_SELF'])); ?>" method="post">
    Username: <input type="text" name="user" value="<?php echo(htmlentities($user)); ?>" /><br />
    Password: <input type="password" name="password" value="" /><br />
    Domain: <input type="text" name="domain" value="<?php echo(htmlentities($domain)); ?>" /><br />
    <input type="submit" value="logon" />
</form>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top