使用本地用户帐户在Windows上进行基于PHP表单的身份验证

时间:2008-09-13 14:57:46

标签: php windows apache authentication sam

我正在运行PHP,Apache和Windows。我没有域设置,所以我希望我的网站基于表单的身份验证使用Windows内置的本地用户帐户数据库(我认为它叫做SAM)。

我知道如果设置了Active Directory,您可以使用PHP LDAP模块在脚本中进行连接和身份验证,但是没有AD就没有LDAP。独立机器的等价物是什么?

3 个答案:

答案 0 :(得分:3)

我也没有找到一个简单的解决方案。有一些使用CreateObject和WinNT ADSI提供程序的示例。但最终他们都进入了 User authentication issues with the Active Directory Service Interfaces WinNT provider。我不是百分百肯定,但我猜测 WSH /网络连接方法有同样的问题。
根据{{​​3}},您应该使用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.

On Windows XP, it is no longer required that a process have the SE_TCB_NAME privilege in order to call LogonUser. Therefore, the simplest method to validate a user's credentials on Windows XP, is to call the LogonUser API.

因此,如果我确定不需要Win9x / 2000支持,我会编写一个将LogonUser暴露给php的扩展。
您可能也对How to validate user credentials on Microsoft operating systems感兴趣。它使用w32api扩展,需要一个支持dll ...我宁愿写一个小的LogonUser-extension ;-)
如果这不可行,我可能会查看IIS的fastcgi模块及其稳定性,让IIS处理身份验证。

编辑:
我还试图利用User Authentication from NT Accounts和php的System.Security.Principal.WindowsIdentity。但是dotnet构造函数似乎不允许将参数传递给对象构造函数,而我的“实验”从GetType()获取程序集(以及它的CreateInstance())失败并出现“未知zval”错误。

答案 1 :(得分:0)

好问题!

我已经考虑过这个......我想不出一个好的解决方案。我能想到的是一个可怕的可怕的黑客攻击。在看到近一天没有人发布这个问题的答案之后,我觉得很糟糕,但是工作的答案还可以。

系统运行时,SAM文件不受限制。有一些DLL注入技巧,你可能会工作,但最终你将最终得到密码哈希,你必须哈希用户提供的密码,以匹配他们。

您真正想要的是尝试根据SAM文件对用户进行身份验证。我认为您可以通过执行以下操作来完成此操作。

  1. 在服务器上创建一个文件共享,并使其成为只有您希望能够登录的帐户才被授予访问权限。
  2. 在PHP中使用system命令调用wsh脚本:使用网站用户提供的用户名和密码来安装共享。记录是否有效,然后卸载驱动器(如果有)。
  3. 以某种方式收集结果。结果可以在脚本的stdout上返回给php,或者希望使用脚本的返回代码。
  4. 我知道它不漂亮,但应该有用。

    我觉得很脏:|

    编辑:调用外部wsh脚本的原因是PHP不允许你使用UNC路径(据我所知)。

答案 2 :(得分:0)

构建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>