ローカル ユーザー アカウントを使用した Windows での PHP フォームベースの認証

StackOverflow https://stackoverflow.com/questions/60585

質問

PHP、Apache、Windows を実行しています。ドメインを設定していないので、Web サイトのフォームベース認証で Windows に組み込まれているローカル ユーザー アカウント データベース (SAM と呼ばれていると思います) を使用したいと考えています。

Active Directory が設定されている場合、PHP LDAP モジュールを使用してスクリプトで接続および認証できることはわかっていますが、AD がなければ LDAP はありません。スタンドアロン マシンに相当するものは何ですか?

役に立ちましたか?

解決

私も簡単な解決策を見つけていません。CreateObject と WinNT ADSI プロバイダーを使用した例があります。でも最終的には全員がぶつかってしまう Active Directory サービス インターフェイス WinNT プロバイダーでのユーザー認証の問題. 。100%確信があるわけではありませんが、 推測 WSH/ネットワーク接続アプローチにも同じ問題があります。
によると Microsoft オペレーティング システムでユーザーの資格情報を検証する方法 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.

Windows XP では、LogonUser を呼び出すためにプロセスが SE_TCB_NAME 特権を持つ必要はなくなりました。したがって、Windows XP でユーザーの資格情報を検証する最も簡単な方法は、LogonUser API を呼び出すことです。

したがって、Win9x/2000 サポートが必要ないと確信している場合は、LogonUser を php に公開する拡張機能を作成するでしょう。
あなたは下記にもご興味がおありかもしれません NTアカウントからのユーザー認証. 。これは w32api 拡張機能を使用しており、サポート DLL が必要です ...むしろ、その小さな LogonUser 拡張機能を書きたいと思います ;-)
それが不可能な場合は、IIS の fastcgi モジュールとその安定性を調べて、IIS に認証を処理させることになると思います。

編集:
私も活用してみました System.Security.Principal.WindowsIdentity そしてphpの com/.net 拡張子. 。しかし、dotnet コンストラクターではオブジェクト コンストラクターにパラメーターを渡すことができないようで、GetType() からアセンブリ (およびそれに伴う CreateInstance()) を取得するという「実験」が「不明な zval」エラーで失敗しました。

他のヒント

良い質問!

これについて少し考えてみました...そして良い解決策が思いつきません。私が思いつくのは、うまくいくかもしれない恐ろしいハックです。この質問に対して 1 日近く誰も回答を投稿していないことを確認した後、私は、回答は悪くても、実用的な回答であれば問題ないと考えました。

SAM ファイルは、システムの稼働中は立ち入り禁止です。DLL インジェクションのテクニックがいくつかあり、それをうまく機能させることもできますが、最終的にはパスワード ハッシュが必要になり、ユーザーが指定したパスワードをハッシュして照合する必要があります。

本当に必要なのは、SAM ファイルに対してユーザーを認証しようとするものです。以下のようなことをすればできると思います。

  1. サーバー上にファイル共有を作成し、ログインできるようにしたいアカウントのみにファイル共有へのアクセスが許可されるようにします。
  2. PHP では、system コマンドを使用して、次のような wsh スクリプトを呼び出します。Web サイトのユーザーが指定したユーザー名とパスワードを使用して共有をマウントします。ドライブが機能するかどうかを記録し、機能する場合はドライブをアンマウントします。
  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>
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top