我正在运行PHP,Apache和Windows。我没有域设置,所以我希望我网站的基于表单的身份验证使用Windows内置的本地用户帐户数据库(我认为它称为SAM)。
我知道,如果设置了Active Directory,则可以使用PHP LDAP模块在脚本中进行连接和身份验证,但是如果没有AD,就没有LDAP。独立计算机的等效功能是什么?
我也没有找到简单的解决方案。有使用CreateObject和WinNT ADSI提供程序的示例。但最终他们都碰上了
Active Directory服务接口WinNT提供程序的用户身份验证问题。我不确定100%,但是我想WSH /网络连接方法也有同样的问题。
根据如何在Microsoft操作系统上验证用户凭据,应使用LogonUser或SSPI。
它还说
1 2 3
| LogonUser Win32 API does not require TCB privilege in Microsoft Windows Server 2003, however, for downlevel compatibility, this is still the best approach.
<p>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.</p> |
因此,如果我确定不需要Win9x / 2000支持,我将编写一个扩展程序,将LogonUser暴露给php。
您可能还对NT帐户的用户身份验证感兴趣。它使用w32api扩展名,并且需要一个支持dll ...我宁愿写那个小的LogonUser-extension ;-)
如果那不可行,我可能会研究IIS的fastcgi模块及其稳定性,然后让IIS处理身份验证。
编辑:
我还尝试利用System.Security.Principal.WindowsIdentity和php的com / .net扩展名。但是dotnet构造函数似乎不允许将参数传递给对象构造函数,并且我的" experiment "从GetType()获取程序集(以及与之创建实例()一起使用)已失败,并出现了" unknown zval "错误。
构建PHP扩展需要大量的硬盘空间投资。由于我已经安装了GCC(MinGW)环境,因此决定采用从PHP脚本启动进程的性能。源代码如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| // 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源代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| 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> |
好问题!
我已经考虑了一下……我想不出一个好的解决方案。我能想到的是一个可能可行的可怕骇客技巧。在看到将近一天没有人发布有关该问题的答案之后,我觉得很糟糕,但是可以解决问题。
在系统运行时,SAM文件超出范围。有一些DLL注入技巧可以使您工作,但最终您只会得到密码哈希,并且您必须对用户提供的密码进行哈希处理,以始终与它们匹配。
您真正想要的是一种尝试根据SAM文件对用户进行身份验证的东西。我认为您可以通过执行以下操作来做到这一点。
在服务器上创建一个文件共享,并对其进行分配,以便仅授予您希望能够以其身份登录的帐户访问权限。
在PHP中,使用system命令调用wsh脚本:使用网站用户提供的用户名和密码安装共享。记录驱动器是否正常运行,然后卸载驱动器。
以某种方式收集结果。结果可以在脚本的stdout上返回给php,或者希望使用脚本的返回码返回。
我知道它不漂亮,但是应该可以。
我觉得很脏:|
编辑:调用外部wsh脚本的原因是PHP不允许您使用UNC路径(据我所记得)。