سؤال

سألت سؤالا قبل بضعة أيام (الوصول إلى SQL Server 2005 من جهاز غير مجال باستخدام مصادقة Windows) التي حصلت على بعض الاقتراحات المثيرة للاهتمام ، ولكن ليست قابلة للاستخدام. أود أن أطرح السؤال مرة أخرى ، لكن أوضح ماهية قيوداتي:

لدي مجال Windows يقوم فيه الجهاز بتشغيل SQL Server 2005 والتي تم تكوينها لدعم مصادقة Windows فقط. أرغب في تشغيل تطبيق عميل C# على جهاز على نفس الشبكة ، ولكن ليس على المجال ، والوصول إلى قاعدة بيانات على مثيل SQL Server 2005.

لا يمكنني إنشاء أو تعديل مستخدمي خادم نظام التشغيل أو SQL على أي من الجهاز ، ولا يمكنني إجراء أي تغييرات على الأذونات أو الانتحال ، ولا يمكنني الاستفادة من Runas.

أعلم أنه يمكنني كتابة تطبيقات Perl و Java التي يمكنها الاتصال بقاعدة بيانات SQL Server باستخدام هذه المعلمات الأربعة فقط: اسم الخادم ، واسم قاعدة البيانات ، اسم المستخدم (في مجال النموذج user) ، وكلمة المرور.

في C# لقد جربت أشياء مختلفة حولها:

string connectionString = "Data Source=server;Initial Catalog=database;User Id=domain\user;Password=password";
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();

وحاول تعيين الأمان المتكامل إلى حقيقي وكاذب ، ولكن لا شيء يبدو أنه يعمل. هل ما أحاول القيام به ببساطة مستحيل في C#؟

شكرا على أي مساعدة ، مارتن

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

المحلول

كما تقول بشكل صحيح ، يمكن لـ JDBC أو Perl على جهاز Linux الاتصال بخادم SQL باستخدام مصادقة Windows وبيانات الاعتماد التي تختلف عن المستخدم الذي تم تسجيله حاليًا. وينطبق الشيء نفسه على أجهزة Windows CE, ، بالمناسبة.

أعتقد أن هذا هو أن هذه ليست مسألة C# ولكن لسائق SQL Server Ole DB. أعتقد أن الطرق المذكورة أعلاه "تظاهر بأنها جهاز Windows باستخدام بعض بيانات الاعتماد المحددة" على مستوى الشبكة ؛ ميزة ، والتي يفتقر إليها برنامج تشغيل SQL Server Ole DB. وبالتالي ، فإن اقتراحي هو البحث عن برنامج تشغيل OLE DB بديل (ربما تجاري؟) يمكنه الوصول إلى قواعد بيانات SQL Server. لست متأكدًا مما إذا كان هناك مثل هذا الشيء.

نصائح أخرى

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

الشيء هو أنني علمت أنه يمكنني تشغيلها بطريقة ما باستخدام Runas لأنني أثبتت ذلك مع SSMS:

C:\WINDOWS\system32\runas.exe /netonly /savecred /user:megacorp\joe.bloggs "C:\Program Files\Microsoft SQL Server\90\Tools\Binn\VSShell\Common7\IDE\SqlWb.exe"

سمحت لي العلم /Netonly بتنفيذ EXE مع بيانات الاعتماد المحلية والوصول إلى الشبكة مع بيانات الاعتماد عن بُعد ، على أي حال ، حصلت على مجموعة النتائج التي توقعتها من الخادم البعيد. كانت المشكلة هي قيادة Runas جعل من الصعب جدًا تصحيح الطلب ، ولم يشم رائحة جيدة.

في النهاية وجدت هذا المقال على مشروع الرمز الذي كان يتحدث عن المصادقة لمعالجة Active Directory ، إليك الفصل الرئيسي الذي يقوم بالانتحال:

    using System;
    using System.Runtime.InteropServices;  // DllImport
    using System.Security.Principal; // WindowsImpersonationContext

    namespace TestApp
    {
        class Impersonator
        {
            // group type enum
            enum SECURITY_IMPERSONATION_LEVEL : int
            {
                SecurityAnonymous = 0,
                SecurityIdentification = 1,
                SecurityImpersonation = 2,
                SecurityDelegation = 3
            }

            // obtains user token
            [DllImport("advapi32.dll", SetLastError = true)]
            static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
                int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

            // closes open handes returned by LogonUser
            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            extern static bool CloseHandle(IntPtr handle);

            // creates duplicate token handle
            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
                int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

            WindowsImpersonationContext newUser;

            /// 
            /// Attempts to impersonate a user.  If successful, returns 
            /// a WindowsImpersonationContext of the new users identity.
            /// 
            /// Username you want to impersonate
            /// Logon domain
            /// User's password to logon with
            /// 
            public Impersonator(string sUsername, string sDomain, string sPassword)
            {
                // initialize tokens
                IntPtr pExistingTokenHandle = new IntPtr(0);
                IntPtr pDuplicateTokenHandle = new IntPtr(0);
                pExistingTokenHandle = IntPtr.Zero;
                pDuplicateTokenHandle = IntPtr.Zero;

                // if domain name was blank, assume local machine
                if (sDomain == "")
                    sDomain = System.Environment.MachineName;

                try
                {
                    const int LOGON32_PROVIDER_DEFAULT = 0;

                    // create token
                    // const int LOGON32_LOGON_INTERACTIVE = 2;
                    const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
                    //const int SecurityImpersonation = 2;

                    // get handle to token
                    bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
                        LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle);

                    // did impersonation fail?
                    if (false == bImpersonated)
                    {
                        int nErrorCode = Marshal.GetLastWin32Error();

                        // show the reason why LogonUser failed
                        throw new ApplicationException("LogonUser() failed with error code: " + nErrorCode);
                    }

                    bool bRetVal = DuplicateToken(pExistingTokenHandle, (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref pDuplicateTokenHandle);

                    // did DuplicateToken fail?
                    if (false == bRetVal)
                    {
                        int nErrorCode = Marshal.GetLastWin32Error();
                        CloseHandle(pExistingTokenHandle); // close existing handle

                        // show the reason why DuplicateToken failed
                        throw new ApplicationException("DuplicateToken() failed with error code: " + nErrorCode);
                    }
                    else
                    {
                        // create new identity using new primary token
                        WindowsIdentity newId = new WindowsIdentity(pDuplicateTokenHandle);
                        WindowsImpersonationContext impersonatedUser = newId.Impersonate();

                        newUser = impersonatedUser;
                    }
                }
                finally
                {
                    // close handle(s)
                    if (pExistingTokenHandle != IntPtr.Zero)
                        CloseHandle(pExistingTokenHandle);
                    if (pDuplicateTokenHandle != IntPtr.Zero)
                        CloseHandle(pDuplicateTokenHandle);
                }
            }

            public void Undo()
            {
                newUser.Undo();
            }
        }
    }

لاستخدامه فقط:

Impersonator impersonator = new Impersonator("username", "domain", "password");

//Connect to and use SQL server

impersonator.Undo();

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

من غير المجدي تحديد اسم المستخدم وكلمة المرور في سلسلة الاتصال لأن تلك التي تعني مصادقة SQL ، وقد حددت بالفعل أن SQL Server يقبل مصادقة Windows فقط.

إذا لم يسمح الخادم بمصادقة SQL ثم فقط إمكانية الاتصال هي استخدام مصادقة Windows ، أي. IntegratedSecurity=true. مما يعني أن عميلك سيصادق على أنه أي بيانات اعتماد تعمل على تشغيل العملية (أو يتم انتحالها حاليًا).

لكي تعمل مصادقة Windows ، يجب عليك اختيار واحد مما يلي:

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

إذا لم تتمكن من جعل مضيف العميل يثق بمجال الخادم ، ولا يمكنك إضافة حسابات NTLM المرآة ، ومسؤول خادم SQL عاقل بما يكفي لعدم تمكين مجهول ، فلن تتمكن من الاتصال.

عليك أن تكوين SQL Server للسماح لمصادقة SQL Server ، IE المصادقة باستخدام اسم المستخدم وكلمة المرور.

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

يمكن أن أكون مخطئًا بالطبع ، لكنني متأكد من أن هذه ليست مشكلة في C# أو .NET. كيف يمكنك تسجيل الدخول على خادم SQL في تطبيق Perl أو Java الخاص بك ؟؟

سأعطيك إجابة Java التي أعرفها أكثر: أستخدم برنامج تشغيل JTDS JDBC مع المعلمات الأربعة المذكورة أعلاه. تطبيق Perl الذي أعرفه أقل ، ولكنه يعمل على مربع Linux ، وهو قادر على الاتصال بنفس المعلمات. لا يمكنني تغيير خادم SQL لدعم مصادقة SQL.

للإجابة على اقتراحات Remus ، لا يمكنني القيام بأي من هذه الأشياء الثلاثة التي يقترحها ، ومع ذلك ، فإن تطبيقات Java و Perl قادرة على الاتصال. أي أفكار أخرى؟

شكرا ، مارتن

فيما يلي رمز النماذج الذي أستخدمه للاتصال من جهاز غير نادي باستخدام برنامج تشغيل JTDS JDBC:

class.forname ("net.sourceforge.jtds.jdbc.driver"). newinstance () ؛ url url = "jdbc: JTDS: sqlserver: // server/database ؛ domain = domain" ؛ conn = drivermanager.getConnection (url ، "user" ، "password") ؛

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