5

PHPを使用してLinuxユーザーのパスワードを変更するための作業パッケージはありますか?

PECL:PAM を使用してみましたが、パスワードを変更しようとするとエラーが発生します。

編集:

PHP コード:

echo pam_chpass($username, $password, $new_pass, &$error) ? 'good' : $error;

PHP (エコー) 出力:

Permission denied (in pam_authenticate)

/var/log/auth から (これらは実際には以前のものです。何らかの理由でログが ATM で動作していないようです):

Jun 11 15:30:20 veda php: pam_unix(php:chauthtok): conversation failed
Jun 11 15:30:20 veda php: pam_unix(php:chauthtok): password - (old) token not obtained
Jun 11 15:30:20 veda php: pam_winbind(php:chauthtok): valid_user: wbcGetpwnam gave WBC_ERR_DOMAIN_NOT_FOUND

他の:

前に詳細が不足していて申し訳ありません。質問を投稿したときは本当に疲れていましたが、それはまだくだらない言い訳です.

4

5 に答える 5

2

オンラインで何時間も調査した結果、非常に優れたオプションを見つけることができなかったため、このハックを実装しました. PHP を使用してパスワードを変更するには、この記事を使用します

また、PECL:PAM パッケージを使用して、ちょっとした検証を追加しています。

このページは安全な HTTPS フォルダにあります (.htaccess による自動リダイレクト)

<?php

$messages = array();

function change_password ($user, $currpwd, $newpwd) {

    // Open a handle to expect in write mode
    $p = popen('/usr/bin/expect','w');

    // Log conversation for verification
    $log = '/tmp/passwd_' . md5($user . time());
    $cmd .= "log_file -a \"$log\"; ";

    // Spawn a shell as $user
    $cmd .= "spawn /bin/su $user; ";
    $cmd .= "expect \"Password:\"; ";
    $cmd .= "send \"$currpwd\\r\"; ";
    $cmd .= "expect \"$user@\"; ";

    // Change the unix password
    $cmd .= "send \"/usr/bin/passwd\\r\"; ";
    $cmd .= "expect \"(current) UNIX password:\"; ";
    $cmd .= "send \"$currpwd\\r\"; ";
    $cmd .= "expect \"Enter new UNIX password:\"; ";
    $cmd .= "send \"$newpwd\\r\"; ";
    $cmd .= "expect \"Retype new UNIX password:\"; ";
    $cmd .= "send \"$newpwd\\r\"; ";
    $cmd .= "expect \"passwd: password updated successfully\"; ";

    // Commit the command to expect & close
    fwrite($p, $cmd); pclose ($p);

    // Read & delete the log
    $fp = fopen($log,r);
    $output = fread($fp, 2048);
    fclose($fp); unlink($log);
    $output = explode("\n",$output);

    return (trim($output[count($output)-2]) == 'passwd: password updated successfully') ? true : false;
}

function process_post() {

    if ((!isset($_SERVER['HTTP_REFERER'])) 
        || (strpos($_SERVER['HTTP_REFERER'], $_SERVER['SCRIPT_NAME']) === FALSE)) {

        echo "GO AWAY!";
        exit();
        return FALSE;

    }

    global $messages;

    $username           = trim($_POST['username']);
    $password_current   = trim($_POST['password_current']);
    $password_new       = trim($_POST['password_new']);
    $password_confirm   = trim($_POST['password_confirm']);

    // Check for blanks
    if ($username == '' || $password_current == '' || $password_new == '' || $password_confirm == '') {
        array_push(&$messages, "ERROR: You cannot leave any field empty.");
        return FALSE;
    }

    // Check username
    if (!ctype_alnum($username)) {
        array_push(&$messages, "ERROR: You've entered an invalid username.");
        return FALSE;
    }

    // Check to see if new password is correctly typed
    if ($password_new != $password_confirm) {       
        array_push(&$messages, "ERROR: New Password and Confirmation do not match.");
        return FALSE;
    }

    // Check if current password is valid (not really neccessary)
    if (!pam_auth($username, $password_current, &$error, FALSE)) {
        if (trim($error) == "Permission denied (in pam_authenticate)")
            array_push(&$messages, "ERROR: You've username/password was not accepted.");    
        else
            array_push(&$messages, "ERROR: " . $error);
        return FALSE;
    }

    if (change_password ($username, $password_current, $password_new))
        array_push(&$messages, "Password Successfully Changed");
    else 
        array_push(&$messages, "ERROR: Password change failed.");

}

if ($_SERVER['REQUEST_METHOD'] == 'POST') process_post();


?><html>
<head>


<title>Passwords</title>

<style type="text/css">

body {
    font-family: Verdana, Arial, sans-serif;
    font-size: 12px;
}

label {
    width: 150px;
    display: block;
    float: left;
}

input {
    float: left;
}

br {
    clear: both;
}

.message {
    font-size: 11px;
    font-weight: bold;
}

.error {
    color:#C00;
}


</style>

</head>


<body>

<h2>Change Passwords</h2>

<form action="<?= $_SERVER['SCRIPT_NAME'] ?>" method="post">

<fieldset>

<? if (count($messages) != 0) { 

    foreach ($messages as $message) { ?>

<p class="message<?= ((strpos($message, 'ERROR:') === FALSE) ? '' : ' error') ?>"><?= $message ?></p>

<? } } ?>

<label>Username: </label>
<input type="text" name="username" /><br />

<label>Current Password:</label>
<input type="password" name="password_current" /><br />

<label>New Password:</label>
<input type="password" name="password_new" /><br />

<label>Confirm Password:</label>
<input type="password" name="password_confirm" /><br />

<input type="reset" value="Reset" /> <input type="submit" value="Submit" />

</fieldset>


</form>


</body>
</html>

この質問/回答もhttps://serverfault.com/questions/150306/how-to-let-users-change-linux-password-from-web-browser/152409#152409に投稿しています

于 2010-06-18T07:56:01.637 に答える
2

wag2369 によって投稿された回答に加えて、次のことを必ず実行してください。

PHP の拡張機能マネージャーである pear をインストールします。

yum install pear

yum から pam-devel をインストールします。

yum install pam-devel

PHP PAM 拡張機能をインストールする

pecl install --alldeps PAM

--alldeps: すべての依存関係を自動的にインストールすることを意味します

ファイル/etc/php.iniを変更し、次のように入力します。

extension=pam.so
pam.servicename="php"

PAM php サービスを許可するには、次の手順を実行します。

cd /etc/pam.d
ln -s login /etc/pam.d/php

Apache を再起動します。

/etc/init.d/httpd restart

/etc/shadow は読み取り可能である必要があります (これはセキュリティ ホールです。考え直してください)

chmod g+r,o+r /etc/shadow

まだインストールされていない場合は期待してインストールする

yum install expect

wag2369 によって投稿されたコードのバグを修正するか、以下の修正されたコードをコピーしてください: array_push(&$error, ...) の代わりに array_push($error,..) を使用してください「passwd: すべての認証トークンが正常に更新されました」を使用します。代わりにチェックします。

<?php
$messages = array();

function change_password ($user, $currpwd, $newpwd) {

    // Open a handle to expect in write mode
    $p = popen('/usr/bin/expect','w');

    // Log conversation for verification
    $log = '/tmp/passwd_' . md5($user . time());
    $cmd = "";
    $cmd .= "log_file -a \"$log\"; ";

    // Spawn a shell as $user
    $cmd .= "spawn /bin/su $user; ";
    $cmd .= "expect \"Password:\"; ";
    $cmd .= "send \"$currpwd\\r\"; ";
    $cmd .= "expect \"$user@\"; ";

    // Change the unix password
    $cmd .= "send \"/usr/bin/passwd\\r\"; ";
    $cmd .= "expect \"(current) UNIX password:\"; ";
    $cmd .= "send \"$currpwd\\r\"; ";
    $cmd .= "expect \"Enter new UNIX password:\"; ";
    $cmd .= "send \"$newpwd\\r\"; ";
    $cmd .= "expect \"Retype new UNIX password:\"; ";
    $cmd .= "send \"$newpwd\\r\"; ";
    $cmd .= "expect \"passwd: all authentication tokens updated successfully.\"; ";

    // Commit the command to expect & close
    fwrite($p, $cmd); pclose ($p);

    // Read & delete the log
    $fp = fopen($log,'r');
    $output = fread($fp, 2048);
    fclose($fp); unlink($log);
    $output = explode("\n",$output);

    return (trim($output[count($output)-2]) == 'passwd: all authentication tokens updated successfully.') ? true : false;
}

function process_post() {

    if ((!isset($_SERVER['HTTP_REFERER'])) 
        || (strpos($_SERVER['HTTP_REFERER'], $_SERVER['SCRIPT_NAME']) === FALSE)) {

        echo "GO AWAY!";
        exit();
        return FALSE;

    }

    global $messages;

    $username           = trim($_POST['username']);
    $password_current   = trim($_POST['password_current']);
    $password_new       = trim($_POST['password_new']);
    $password_confirm   = trim($_POST['password_confirm']);

    // Check for blanks
    if ($username == '' || $password_current == '' || $password_new == '' || $password_confirm == '') {
        array_push($messages, "ERROR: You cannot leave any field empty.");
        return FALSE;
    }

    // Check username
    if (!ctype_alnum($username)) {
        array_push($messages, "ERROR: You've entered an invalid username.");
        return FALSE;
    }

    // Check to see if new password is correctly typed
    if ($password_new != $password_confirm) {       
        array_push($messages, "ERROR: New Password and Confirmation do not match.");
        return FALSE;
    }

    // Check if current password is valid (not really neccessary)
    $error = '';
    if (!pam_auth($username, $password_current, $error, FALSE)) {
        if (trim($error) == "Permission denied (in pam_authenticate)")
            array_push($messages, "ERROR: Your username/password was not accepted.");    
        else
            array_push($messages, "ERROR: " . $error);
        return FALSE;
    }

    if (change_password ($username, $password_current, $password_new))
        array_push($messages, "Password Successfully Changed");
    else 
        array_push($messages, "ERROR: Password change failed.");

}

if ($_SERVER['REQUEST_METHOD'] == 'POST') process_post();


?><html>
<head>


<title>Passwords</title>

<style type="text/css">

body {
    font-family: Verdana, Arial, sans-serif;
    font-size: 12px;
}

label {
    width: 150px;
    display: block;
    float: left;
}

input {
    float: left;
}

br {
    clear: both;
}

.message {
    font-size: 11px;
    font-weight: bold;
}

.error {
    color:#C00;
}


</style>

</head>


<body>

<h2>Change Passwords</h2>

<form action="<?= $_SERVER['SCRIPT_NAME'] ?>" method="post">

<fieldset>

<? if (count($messages) != 0) { 

    foreach ($messages as $message) { ?>

<p class="message<?= ((strpos($message, 'ERROR:') === FALSE) ? '' : ' error') ?>"><?= $message ?></p>

<? } } ?>

<label>Username: </label>
<input type="text" name="username" value="halaluya" /><br />

<label>Current Password:</label>
<input type="password" name="password_current" value="dev0te@m" /><br />

<label>New Password:</label>
<input type="password" name="password_new" value="123" /><br />

<label>Confirm Password:</label>
<input type="password" name="password_confirm" value="123" /><br />

<input type="reset" value="Reset" /> <input type="submit" value="Submit" />

</fieldset>


</form>


</body>
</html>
于 2011-03-02T07:38:06.153 に答える
1

PAM パスワードを PHP から直接変更するには、システム ファイルとサービスに多くのアクセスが必要です。これは、PAM がデフォルトで pam_unix モジュールを使用し、root が所有するシステム ファイルにユーザー資格情報を保存するためです。この問題を解決する良い方法は、pam_ldap モジュールを使用するように PAM をセットアップすることです。このように PAM と LDAP サーバーを使用してユーザーを認証します。次に、PHP から、ユーザー資格情報を使用して LDAP サーバーにバインドし、パスワードを変更できます。このような変更の承認は、LDAP 承認メカニズムによって処理されます。(階層化されたセキュリティを提供するために、アプリケーションは承認規則も適用する必要があります)

上記の構成は簡単ではありません。最初に LDAP サーバーをセットアップしてから、すべてのユーザー データをシステム ファイル (passwd、shadow) から LDAP ディレクトリに移行する必要があります。(そのための自動化ツールがあります)。最後に、pam_ldap モジュールをインストールしてセットアップする必要があります。上記のプロセスで設定を誤ると、深刻なセキュリティ上の問題が発生する可能性があります。

この方法では、アプリケーションを介して LDAP サーバーを Web に公開することにも注意してください。LDAP 認証または承認メカニズムに影響を与える可能性のあるセキュリティの問題は、システムのセキュリティにも影響します。

資力:

LDAP を使用して POSIX アカウントを保存する:

http://www.ibm.com/developerworks/linux/library/l-openldap/

認証に LDAP を使用するように PAM をセットアップします。

http://wiki.debian.org/LDAP/PAM

于 2012-05-19T17:24:01.473 に答える
0

PHPを使用してLinuxユーザーのパスワードを変更するための作業パッケージはありますか?

これは本当に、本当に危険です。リスクを理解していると仮定すると、パスワードの変更を許可する特権レベルで実装する必要がある変更を適用する前に、多くの制約を構築する必要があることに気付くでしょう。つまり、これを実行するコードは、スタンドアロンの実行可能ファイルでなければなりません。 setuid executin を実行するか、php コードから sudo 経由で呼び出します。

もちろん、スタンドアロン コードを PHP で記述できない理由はありません。それは、PHP の PAM バインディングが (少なくとも最後にこれを見たときは) かなり未熟だったという事実以外にはありません。

chpasswd プログラム (Redhat およびその他のディストリビューションで利用可能) を確認するか、proc_open('/usr/bin/passwd'... を使用して) プロンプトを読み、正しく応答することをお勧めします。

HTH

C.

于 2010-06-13T22:42:21.460 に答える
0

RSBAC パスワードを使用できます。

$ret = system("echo \"newpass newpass\" | rsbac_password -n");

if ($ret)
    echo "fail.";
else
    echo "done!";

とても簡単です。

于 2010-07-19T12:55:00.513 に答える