Z mojego czytania o podszywaniu się pod użytkownika w systemie Windows należy poprawnie użyć logonu LOGON32_LOGON_NEW_CREDENTIALS do podszywania się pod użytkownika w bazie danych. Używając ładnego opakowania personalnego Matta Johnsona (pierwotnie opublikowanego pod numerem here, a następnie wypolerowanego pod numerem here), próbowałem to przetestować - oto mój cały program, z wyjątkiem stałych definiujących moją konkretną domenę DOMAIN, USER, PWD i CONN_STRING.Co jest magią podszywania się pod Windows przy pomocy LOGON32_LOGON_NEW_CREDENTIALS?
using System;
using System.Data.SqlClient;
using SimpleImpersonation;
namespace ImpersonationDemo
{
class Program
{
private static SqlConnection _connection;
static void Main(string[] args)
{
using (Impersonation.LogonUser(
DOMAIN, USER, PWD, LogonType.NewCredentials))
{
GetOpenConnection();
CheckDbCredentials();
CloseConnection();
}
Console.WriteLine("Press return to exit");
Console.ReadLine();
}
private static void CheckDbCredentials()
{
using (
var command = new SqlCommand(
"SELECT nt_user_name, SUSER_SNAME() "
+"FROM sys.dm_exec_sessions WHERE session_id = @@SPID",
_connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine("{0}, {1}",
reader.GetString(0), reader.GetString(1));
}
}
}
}
private static void GetOpenConnection()
{
_connection = new SqlConnection(CONN_STRING);
_connection.Open();
}
private static void CloseConnection()
{
_connection.Close();
}
}
}
Ale to nie działa. Dane wyjściowe raportów mi (mój bazowy zalogowany użytkownik) zarówno z nt_user_name
i SUSER_NAME()
. (I SQL Profiler zgłasza dokładnie to samo, zapytanie w kodzie jest po prostu wygodnym sposobem zobaczenia, co SQL Profiler mi mówi.)
Jeśli zmienię z LogonType.NewCredentials
na LogonType.Interactive
(te wyliczenia mają wartości, których można się spodziewać, zdefiniowane na pinvoke.net), to działa - powyższy kod zgłasza prawidłowe podszywanie się do DOMAIN i USER. Ale oznacza to również podszywanie się pod obecną sesję, której nie chcę - chcę tylko podszyć się pod połączenie DB.
myślałem znalazłem jedną usterkę w wyżej - Johnsona personifikacji wrapper twarde kody dostawcy logowania jako LOGON32_PROVIDER_DEFAULT
, gdy LogonUser API wyraźnie stwierdza, że typ LOGON32_LOGON_NEW_CREDENTIALS
logowania jest obsługiwana tylko przez dostawcę LOGON32_PROVIDER_WINNT50
logowania. Więc złapałem źródło i dodałem parametr pozwalający na określenie wymaganego dostawcy logowania ... ale to nie miało znaczenia.
Więc czego mi brakuje?
Cofanie się o krok od wydania: jeśli zamierzasz zalogować się w instancji serwera DB za pomocą Zintegrowanych zabezpieczeń, nie powinieneś w ogóle polegać na podszywaniu się; w takim przypadku ** 1. ** przy użyciu loginu SQL Server będzie łatwiejszą opcją. Jeśli używasz Zintegrowanego bezpieczeństwa, ** 2. ** po prostu pozwól użytkownikom docelowym zalogować się (ale ogranicz ich prawa do serwera i bazy danych w miarę możliwości); lub (jeszcze lepiej :) ** 3. ** tylko pozwala usłudze uzyskać dostęp do bazy danych i mieć dostęp do aplikacji tylko do usługi, która wykonuje własne uwierzytelnienie i autoryzację. – stakx
Doceniam sugestie @stakx; jednak w tym przypadku nie mam elastyczności do wprowadzania zmian architektonicznych. A poza tym, być może nie będę mógł ponownie zasnąć w nocy, dopóki nie dowiem się, dlaczego powyższe zawodzi :-)! –
Co się stanie, jeśli użyjesz C, aby uzyskać token LOGON32_LOGON_NEW_CREDENTIALS, a następnie uruchomić odrębny proces z tokenem, aby wykonać pracę SQL w twoim imieniu? (Nowy proces może być w języku C#.) –