web-dev-qa-db-ja.com

PHPを使用して/ etc / shadowに対してユーザーを認証する最も安全な方法は?

Horde環境をセットアップしていて、システムアカウントを使用したいので、この質問は私にとって重要になりました。検索を行うと、主に4つの方法が見つかりましたが、これらにはすべて欠点があるようです。どれが最も安全であるか、またはいくつかの代替案が欠けているのではないかと思っています。

  • 方法1:PAM(PHP)を使用する

    Hordeは、PAMライブラリを利用する認証プラグインを提供しています。正常に動作しますが、Webサーバーには/ etc/shadowへの読み取りアクセスが必要です。これは、ダウンロード用のパスワードファイルを公開するのと同じくらい安全であるという声明が見つかりました。

  • 方法2:/ bin/su(PHP)を使用する

    さらに、Hordeは、/bin/suでfopen(ファイルオープン)を呼び出し、この「ファイル」にパスワードを書き込むことにより、/bin/su -c /bin/true $usernameを使用して認証するモジュールを提供します。現在、これは私には機能しません。 AFAIK、これはおそらく/bin/suが端末でのみ機能するように構成されているためです。この/bin/suの使用を許可することは可能であると読みましたが、安全ではありません。

  • 方法3:外部プログラムを使用する(コマンドライン)

    PAMライブラリを利用し、PHPによって呼び出される小さなプログラムを書くこともできます。 SUIDを使用すると、誰も/etc/shadowにアクセスできませんでした。ただし、パスワードを引数として渡すか、自分のプログラムにパイプする必要があります。これもセキュリティ上のリスクがあると言われています。 (これが理由だと思いますが、/bin/suがデフォルトで許可していないのはなぜですか。)

  • 方法4:外部プログラムを使用する(ローカルネットワーク)

    方法3と同じですが、通信はUNIXソケットまたはTCP接続を介して行うことができます。これが#3よりも安全かどうかはわかりません。おそらく、ttyよりもローカルネットワーク接続をスパイするのが難しいかどうかという質問に相当します。

最初のオプションが良い考えではない理由は明らかだと思います。でも、他の人の何が悪いのかわからないので、簡単な説明があれば嬉しいです。

4
xwst

方法1:2秒間考えてみると、これらのコメントは本質的に正しいので、私は好きではありません。悪用可能かどうかに関係なく、/etc/shadowファイルを公開するサーフェスを作成しているのですが、そうしなければならないのは好きではありません。

方法2:も不適切です。ファイルにパスワードをエンコードすることはばかげています。それらをパイプに通すことも同様に危険なようです。

方法3:はおそらく私が行う方法であり、独自のソリューションを最初から作成する必要はないと思います。数分のグーグルで、誰かがlibpamAPIを使用してまとめたこの実装を見つけました。

c実装

C実装の抜粋-pam.c

#include <security/pam_appl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct pam_response *reply;

int null_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) {

        *resp = reply;
        return PAM_SUCCESS;

}

static struct pam_conv conv = { null_conv, NULL };

int main(int argc, char *argv[]) {

        int retval;
        char *user, *pass;   

        if(argc == 3) {

                user = argv[1];
                pass = strdup(argv[2]);

        } else { 

                fprintf(stderr, "Usage: login [username] [password]\n");
                exit(1);

        }

        return authenticate("system-auth", user, pass);

}   

int authenticate(char *service, char *user, char *pass) {

        pam_handle_t *pamh = NULL;
        int retval = pam_start(service, user, &conv, &pamh);

        if (retval == PAM_SUCCESS) {

                reply = (struct pam_response *)malloc(sizeof(struct pam_response));
                reply[0].resp = pass;
                reply[0].resp_retcode = 0;

                retval = pam_authenticate(pamh, 0);

                if (retval == PAM_SUCCESS)
                        fprintf(stdout, "Authenticated\n");

                else
                        fprintf(stdout, "Not Authenticated\n");

                pam_end(pamh, PAM_SUCCESS);

                return ( retval == PAM_SUCCESS ? 0:1 );

        }

        return ( retval == PAM_SUCCESS ? 0:1 );
} 

それをコンパイルするコマンド

$ gcc -g -lpam -o chkpasswd pam.c

実行例

$ ./chkpasswd myusername mypassword

少しの努力で、このアプローチはHordeのニーズに合わせて適応できると思います。

PHP実装

このアプローチの別の方法として、PHPで独自にロールすることもできます。このPAMライブラリは、PECLWebサイトであなたが望むもののように見えます。

また、Moodleプロジェクトがそれをどのように行うかについても見ていきます。ここで説明します。

セキュリティの観点からのPAM

PAMの目的を見ると、APIインターフェースは、APIのユーザーが使用できるように、/etc/shadowなどの下位レベルのエンティティへのアクセスが不要になるように設計されていると思います。これについては、Gentoo wikiのこの記事のタイトル: PAM、セクション:PAMのしくみ で少し説明されています。

exerpt from How PAM works

したがって、ユーザーがWebアプリケーションなどに対して自分自身を認証したい場合、このWebアプリケーションはPAMを呼び出し(ユーザーIDとおそらくパスワードまたはチャレンジを渡す)、PAMリターンをチェックして、ユーザーが認証され、アクセスが許可されているかどうかを確認しますアプリケーション。認証する場所(中央データベースやLDAPサーバーなど)を確認するのは、基本的にPAMのタスクです。

PAMの強みは、誰もがPAMモジュールを構築して、PAM対応のサービスまたはアプリケーションと統合できることです。企業が認証用の新しいサービスをリリースした場合、そのサービスと対話するPAMモジュールを提供するだけで、PAMを使用するすべてのソフトウェアがこのサービスとすぐに連携できます。これらのソフトウェアタイトルを再構築または拡張する必要はありません。

方法4:これも良い代替案です。認証を行うためにネットワーク経由でLDAPなどにアクセスするために必要な呼び出しを行うには、ライブラリなどへのアクセスが良好である必要があります。 LDAPサーバーは、Hordeのインストールと同じシステムにセットアップして、Hordeが使用できるように構成することもできます。

これにより、潜在的に、Hordeが消費するLDAPサービスにシステムを「ラップ」することにより、基盤となるシステムの認証にアクセスできるようになります。

参考文献

3
slm