Проверка подлинности на основе форм PHP в Windows с использованием учетных записей локальных пользователей

Я использую PHP, Apache и Windows. У меня нет настройки домена, поэтому я хотел бы, чтобы при проверке подлинности на основе форм моего сайта использовалась локальная база данных учетных записей пользователей, встроенная в Windows (я думаю, она называется SAM).

Я знаю, что если Active Directory настроен, вы можете использовать PHP-модуль LDAP для подключения и аутентификации в вашем скрипте, но без AD нет LDAP. Что является эквивалентом для автономных машин?

3 ответа

Решение

Я не нашел и простого решения. Есть примеры использования CreateObject и провайдера WinNT ADSI. Но в конечном итоге все они сталкиваются с проблемами аутентификации пользователя с поставщиком WinNT интерфейсов службы Active Directory. Я не уверен на 100%, но я думаю, что подход WSH/ подключение к сети имеет ту же проблему.
В соответствии с Как проверить учетные данные пользователя в операционных системах Microsoft, вы должны использовать LogonUser или SSPI.
Это также говорит

 Winon API LogonUser Win32 не требует привилегии TCB в Microsoft Windows Server 2003, однако для обеспечения более низкой совместимости это по-прежнему лучший подход.

В Windows XP больше не требуется, чтобы процесс имел привилегию SE_TCB_NAME для вызова LogonUser. Поэтому самый простой метод проверки учетных данных пользователя в Windows XP - это вызов API LogonUser.

Поэтому, если бы я был уверен, что поддержка Win9x/2000 не нужна, я бы написал расширение, которое выставляет LogonUser на php.
Вы также можете быть заинтересованы в аутентификации пользователей из учетных записей NT. Он использует расширение w32api и нуждается в поддержке DLL... Я бы лучше написал это маленькое расширение LogonUser;-)
Если это невозможно, я, вероятно, посмотрю на модуль fastcgi для IIS и на то, насколько он стабилен, и позволю IIS обработать аутентификацию.

редактировать:
Я также пытался использовать System.Security.Principal.WindowsIdentity и расширение php com/.net. Но конструктор dotnet, по-видимому, не позволяет передавать параметры конструктору объектов, и мой "эксперимент" по получению сборки (а вместе с ней CreateInstance()) из GetType() завершился с ошибкой "unknown zval".

Хороший вопрос!

Я подумал об этом... и не могу придумать хорошего решения. То, о чем я могу думать, это ужасный ужасный хак, который может сработать. Увидев, что никто не опубликовал ответ на этот вопрос в течение почти дня, я понял, что это плохо, но с рабочим ответом все будет в порядке.

Файл SAM запрещен во время работы системы. Есть некоторые хитрости DLL-инъекций, которые вы можете использовать, но в итоге вы просто получите хэши паролей и вам придется хэшировать пароли, предоставленные пользователем, чтобы они соответствовали им в любом случае.

То, что вы действительно хотите, это то, что пытается аутентифицировать пользователя по файлу SAM. Я думаю, что вы можете сделать это, выполнив что-то вроде следующего.

  1. Создайте общий доступ к файлам на сервере и сделайте так, чтобы доступ к нему имели только те учетные записи, для которых вы хотите иметь возможность войти в систему.
  2. В PHP используйте системную команду для вызова wsh-скрипта, который: монтирует общий ресурс, используя имя пользователя и пароль, предоставленные пользователем веб-сайта. записывает, если он работает, а затем размонтирует диск, если это работает.
  3. Соберите результат как-нибудь. Результат может быть возвращен php либо на стандартный вывод скрипта, либо, мы надеемся, используя код возврата для скрипта.

Я знаю, что это не красиво, но это должно сработать.

Я чувствую себя грязным:|

Редактировать: причина вызова внешнего wsh-скрипта в том, что PHP не позволяет использовать UNC-пути (насколько я помню).

Создание расширения PHP требует довольно больших затрат с точки зрения места на жестком диске. Поскольку у меня уже установлена ​​среда GCC (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>
Другие вопросы по тегам