我正在运行 PHP、Apache 和 Windows。我没有域设置,所以我希望我的网站的基于表单的身份验证使用 Windows 内置的本地用户帐户数据库(我认为它称为 SAM)。
我知道如果设置了 Active Directory,您可以使用 PHP LDAP 模块在脚本中进行连接和身份验证,但没有 AD 就没有 LDAP。独立机器的等价物是什么?
我正在运行 PHP、Apache 和 Windows。我没有域设置,所以我希望我的网站的基于表单的身份验证使用 Windows 内置的本地用户帐户数据库(我认为它称为 SAM)。
我知道如果设置了 Active Directory,您可以使用 PHP LDAP 模块在脚本中进行连接和身份验证,但没有 AD 就没有 LDAP。独立机器的等价物是什么?
我也没有找到一个简单的解决方案。有使用 CreateObject 和 WinNT ADSI 提供程序的示例。但最终他们都遇到
了 Active Directory 服务接口 WinNT 提供程序的用户身份验证问题。我不是 100% 确定,但我猜WSH/网络连接方法也有同样的问题。
根据如何在 Microsoft 操作系统上验证用户凭据,您应该使用 LogonUser 或 SSPI。
它还说
因此,如果我确定不需要 Win9x/2000 支持,我会编写一个将 LogonUser 暴露给 php 的扩展。在 Microsoft Windows Server 2003 中,LogonUser Win32 API 不需要 TCB 权限,但是,为了向下兼容,这仍然是最好的方法。在 Windows XP 上,不再需要进程具有 SE_TCB_NAME 权限才能调用 LogonUser。因此,在 Windows XP 上验证用户凭据的最简单方法是调用 LogonUser API。
编辑:
我也尝试过利用System.Security.Principal.WindowsIdentity和 php 的com/.net 扩展名。但是 dotnet 构造函数似乎不允许将参数传递给对象构造函数,并且我从 GetType() 获取程序集(以及 CreateInstance())的“实验”因“未知 zval”错误而失败。
好问题!
我已经考虑过了……我想不出一个好的解决方案。我能想到的是一个可怕的骇人听闻的骇客,它可能会奏效。在看到将近一天没有人发布这个问题的答案后,我认为这是一个不好的答案,但可以工作的答案是可以的。
SAM 文件在系统运行时不受限制。有一些 DLL 注入技巧,您可能可以使用它们,但最终您只会得到密码哈希,并且无论如何您都必须对用户提供的密码进行哈希处理以匹配它们。
您真正想要的是尝试根据 SAM 文件对用户进行身份验证的东西。我认为您可以通过执行以下操作来做到这一点。
我知道它不漂亮,但它应该工作。
我觉得脏:|
编辑:调用外部 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>