鑑於 root 使用者在環境變數中設定了一些憑證(例如 API 金鑰),並且給定非特權使用者 John,我如何讓 John 執行一個腳本用途說 API 金鑰沒有將其值洩漏給 John 的風險?
答案1
問題好像有點沒有重點。
問題是,本身, 討論從「超級使用者環境變數」(即「根環境變數」)取得值。我什至不確定這意味著什麼。您是說 John 應該從以「root」身分登入的(另一個)使用者的環境中取得值,或透過
su
或以「root」身分執行的使用者的環境中取得值sudo
嗎?或者你在談論一個環境過程 (可能是後台進程)以「root」身分執行?但是,無論您想到什麼細節,這聽起來似乎關鍵是非常動態且短暫的。由於我不明白這意味著什麼,所以我不會說這是不可能的,但聽起來很困難。
但隨後在評論中您談到使腳本可執行但不可讀。這表示您願意將金鑰硬編碼到腳本中,只要非 root 使用者無法讀取它。這表示密鑰非常靜態,很少發生變化,因此您願意在每次密鑰更改時修改腳本。
大學與大學關於這個主題有一個很長的話題: 腳本可以執行但不可讀嗎? 遺憾的是,大多數答案是否定的,或者是偏離、轉移注意力或變通辦法,其中一些比其他更有效。例如,桑塔納建議建立一個條目,
/etc/sudoers
允許 John跑步具有提升權限的腳本,但無法以自己的身分讀取它。但是,如果腳本不需要提升的權限(除了取得金鑰),您不希望以提升的權限來執行它。然而,關於這個相關問題(關於超級用戶),我提出了一種笨拙的方法,透過將腳本包裝在 C 程式中來使腳本可執行但不可讀。正如我在該答案中解釋的那樣,這種技術並不是萬無一失的;資訊可能會透過多種方式洩漏出去。
恕我直言,最合理/最合理的解釋是密鑰保存在約翰無法讀取的檔案中。實現這種安排的傳統方式是 setUID 和/或 setGID。 (
sudo
也很有用。)
下面是如何執行此操作的範例。寫一個 C 程序,如下所示:
#include <stdio.h> #include <stdlib.h> #定義KEY_FILE (適當的路徑名) #定義腳本 (適當的路徑名) 主要的() { 檔案 *key_fp; 字符鍵[80]; (酌情調整) gid_t gid; uid_t uid; 字元 *args[10]; (酌情調整) key_fp = fopen(KEY_FILE, "r"); if (key_fp == NULL) { 錯誤(KEY_FILE); 退出(1); } (您要讀取和驗證的程式碼鑰匙) fclose(key_fp); if (setenv("KEY", key, 1) != 0) { fprintf(stderr, "setenv() 出現問題。\n"); 退出(1); } gid = getgid(); uid = getuid(); // 使用 // if (setresgid(gid, gid, gid) != 0 || setresuid(uid, uid, uid) != 0) // 如果它們可用;否則 if (setregid(gid, gid) != 0 || setreuid(uid, uid) != 0) { fprintf(stderr, "刪除權限時出現問題。\n"); 退出(1); } args[0] = "腳本名稱"; (酌情調整) 參數[1] = NULL; execv(腳本,參數); 錯誤(腳本); 退出(1); }
定義KEY_FILE
為包含金鑰的檔案的完整路徑名,並定義SCRIPT
為包含腳本的檔案的完整路徑名。確保 John 具有對腳本的讀取權限,但沒有密鑰檔案的讀取權限,且他對任一路徑中的任何目錄都沒有寫入權限。透過設定該程式 setUID 和/或 setGID 來安排程式能夠讀取金鑰檔案。它將讀取金鑰,將其插入環境中,刪除權限,然後執行腳本。 (您可能需要修改上面的程式碼,以便將提供給程式的命令列參數傳遞給腳本。)
如上所述,該腳本將使用 John 的 UID 和 GID 運行,但金鑰位於環境中。在某些系統上,John 可以從或使用讀取腳本的環境。如果是這樣,讓腳本立即將金鑰複製到本機(非匯出)變數並取消設定變數可能會有所幫助。/proc/(pid_of_script)/environ
ps
KEY
腳本將密鑰傳遞給程式可能是安全的
- 透過管道(例如),
printf "%s" (key_value) | (program)
- 透過此處的文檔,或
- 通過這裡的字串。
上面提到了透過環境傳遞價值的風險。避免將其作為命令行參數傳遞,因為這肯定可以被ps
.
如果你想讓程式可以透過 運行sudo
,你可能需要對 John 的 UID 和 GID 進行硬編碼,因為sudo
設定了真實的 ID 和有效的 ID。