暴露純文本(密碼內容)的唯一機會是在進行身份驗證時詢問用戶密碼的時候。有一些可用的API函數能夠減少這種風險,包括加密,這應該在獲得用戶密碼之後立即進行。
密碼處理的第一條原則是,絕對不要將純文本的密碼寫到磁盤上——即使是你會立即刪掉的臨時文件。一旦數據到了磁盤上,你在使用之後就很難保證數據沒有丟失。
雖然這個原則看起來似乎很簡單,但是你必須要記住:Linux使用的是虛擬內存。如果你加載了交換分區,內存(裡的內容)會在任何時候被寫到磁盤上。為了防止密碼緩沖區被寫到交換分區上,你可以使用mlock API調用:
const intsz = 25; char *buf = malloc(sz); mlock(buf, sz); memset(buf, 0, sz);
為了確保緩沖區真的被鎖定了,你必須至少向每個內存頁寫入一個值。
另一個重要的原則是,決不要將輸入的密碼反饋到終端上。你可以編寫自己的函數或者使用getpass函數,它像下面這樣工作:
const char prompt[] = "Password: "; char *pword = NULL; pword = getpass(prompt);
有時候你無法使用getpass。在這樣的情況下,你將需要編寫自己的getpass函數。下面就是一個例子:
#include #include ssize_t my_getpass (char **lineptr, size_t *n, FILE *stream) { structtermios old, new; intnread; /* Turn echoing off and fail if we can't. */ if (tcgetattr (fileno (stream), &old) != 0) return -1; new = old; new.c_lflag &= ~ECHO; if (tcsetattr (fileno (stream), TCSAFLUSH, &new) != 0) return -1; /* Read the password. */ nread = getline (lineptr, n, stream); /* Restore terminal. */ (void) tcsetattr (fileno (stream), TCSAFLUSH, &old); return nread; } return nread; }
很顯然,傳遞到函數裡的緩沖區應該首先被鎖定。
PAM是一個模塊化的系統,它將驗證、密碼管理、會話管理,以及帳號管理抽象出來。它授權被編寫用來同PAM一起工作的應用程序來使用各種模塊,並允許這些模塊被卸載或者被別的模塊替換,而不需要重新編寫應用程序。
PAM允許你以一種安全的方式進行本文所討論的所有事情,而不要在你為不同系統編寫新應用程序的時候從頭再來。除非有什麼特定的理由不使用它,我都建議你使用PAM。你會發現它要比實現一個更老的系統或者編寫一個你自己的系統更加理想。