正確處理Linux里的密碼
在Linux里,有很多API函數是用來處理密碼的,但是這只能解決一半的問題。你不得不使用好的密碼處理辦法。例如,只有在絕對必要的時候才使用純文本密碼這種(安全)策略。
暴露純文本(密碼內容)的唯一機會是在進行身份驗證時詢問用戶密碼的時候。有一些可用的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 <termios.h>
#include <stdio.h>
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一起工作的應用程序來使用各種模塊,并允許這些模塊被卸載或者被別的模塊替換,而不需要重新編寫應用程序。