使用 PHP 針對 /etc/shadow 對使用者進行身份驗證的最安全方法?
這個問題對我來說很重要,因為我正在設置一個部落環境並想使用系統帳戶。做了一些搜尋,我發現主要有 4 種方法,它們似乎都有一些缺點。現在我想知道,哪一個最安全,或者我是否缺少一些替代方案。
- 方法一:使用 PAM (PHP)
Horde 提供了一個使用 PAM 庫的身份驗證外掛。工作正常,但網路伺服器需要對 /etc/shadow 的讀取權限。我發現一些聲明說這與發布密碼文件以供下載一樣安全。
- 方法二:使用 /bin/su (PHP)
此外,Horde 提供了一個模組,用於
/bin/su
通過呼叫 fopen(文件打開)/bin/su -c /bin/true $username
並將密碼寫入此“文件”來進行身份驗證。目前,這對我不起作用。AFAIK,這可能是因為/bin/su
配置為僅在終端中工作。我讀到可以允許這種用法/bin/su
,但它是不安全的。
- 方法三:使用外部程序(命令行)
我可以編寫一個使用 PAM 庫並由 PHP 呼叫的小程序。使用 SUID,沒有人可以訪問
/etc/shadow
. 但是,我必須將密碼作為參數傳遞給我的程序或將其通過管道傳遞到我的程序中,這又被認為是一種安全風險。(我想這就是原因,為什麼/bin/su
預設不允許它。)
- 方法四:使用外部程序(本地網路)
與方法 3 相同,但可以通過 unix 套接字或 tcp 連接進行通信。我不知道這是否比#3更安全,可能相當於監視本地網路連接是否比tty更難的問題!?
我認為很清楚,為什麼第一個選項不是一個好主意。但我不知道其他人有什麼問題,所以我會很高興有一些簡短的解釋。
**方法1:**我不喜歡僅僅因為在2秒內思考這些評論基本上是正確的。您正在創建一個暴露
/etc/shadow
文件的表面,無論它是否可利用,我只是不喜歡這樣做。**方法二:**也不好。在文件中編碼密碼只是愚蠢的。將它們通過管道似乎同樣危險。
**方法3:**可能是我要走的路,我認為您不必從頭開始編寫自己的解決方案。在幾分鐘的Google搜尋中,我發現有人使用 libpam API 組合在一起的這個實現。
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
我想只要稍加努力,這種方法就可以適應你對部落的需求。
PHP 實現
作為這種方法的另一種替代方法,您可能會在 PHP 中推出自己的方法。我在 PECL 網站上找到了這個 PAM 庫,看起來像你想要的。
我還要看看 Moodle 項目是如何做到的。在這裡討論。
從安全形度看 PAM
看看 PAM 的目的,我希望 API 介面被設計為不需要訪問較低級別的實體,例如 ,
/etc/shadow
以便 API 的使用者可以使用它。這篇文章在 Gentoo wiki 上進行了一些討論,標題為:PAM,部分:PAM 的工作原理。因此,當使用者想要針對 Web 應用程序進行身份驗證時,該 Web 應用程序會呼叫 PAM(傳遞使用者 ID 以及可能的密碼或質詢)並檢查 PAM 返回以查看使用者是否已通過身份驗證並允許訪問應用程序。PAM 的基本任務是查看在哪裡進行身份驗證(例如中央數據庫或 LDAP 伺服器)。
PAM 的優勢在於每個人都可以建構 PAM 模組以與任何啟用 PAM 的服務或應用程序集成。如果一家公司發布了一項新的身份驗證服務,它所要做的就是提供一個與其服務互動的 PAM 模組,然後所有使用 PAM 的軟體都可以立即使用該服務:無需重建或增強這些軟體標題。
**方法4:**也是一個不錯的選擇。應該有對庫的良好可訪問性,以便進行必要的呼叫以通過網路訪問諸如 LDAP 之類的東西來為您進行身份驗證。LDAP 伺服器也可以安裝在與 Horde 安裝相同的系統上,將其配置為僅供 Horde 使用。
這將使您能夠訪問底層系統的身份驗證,可能通過將其“包裝”在 LDAP 服務中供 Horde 使用。
參考