學shell到現在了,一直以為自己不會犯一個大家常說的非常二的問題,結果這本書最後的時候犯了個十分2的事,晚節不保啊!!!我在測試檔案路徑下除了萬用字元*和?外還能用啥正則那樣的東西,結果就在$HOME下執行了rm .* 。。。好吧,蛋疼了一下午!還木找回任何一個設定檔。警示後人,千萬別使用rm試萬用字元!任何時候小心使用rm!
第十四章shell可移植性議題和擴充
可以先通讀這篇文章。
想寫出好的可移植性shell,不僅要瞭解各種shell版本間的差異,還要有很多編程技巧,比如盡量從環境變數中擷取需要的資訊等。
第十五章安全的shell指令碼:起點
安全性shell指令碼的提示:
1、不要將目前的目錄(點號)置於PATH下。可執行程式應該只能放在標準的系統目錄下,將目前的目錄放在PATH裡,無疑是開啟特洛伊木馬(Trojan Horse)的大門。
2、為bin目錄設定保護。確認$PATH下的每一個目錄都只有它的擁有者可以寫入,其餘任何人都不能。用樣的道理也應該應用於bin目錄裡所有的程式。
3、寫程式前,先想清除。花點時間想想你要做什麼,該如何實行。不要一開始就在文字編輯器上寫。錯誤與失敗的優雅處理也應該設計在程式裡。
4、應對所有輸入參數檢查其有效性。如果期待的是數字,那就驗證它是數字,並且是否在要求的範圍內。其他的需要也是這樣檢測。
5、對所有可返回錯誤的命令,檢查錯誤處理代碼。不在你預期內的失敗情況,很可能是有問題的強迫失敗,導致指令碼出現不當的行為。例如,如果參數為NFS載入磁碟或面向字元的裝置檔案時,即便是以root的身份執行,也可能導致有些命令失敗。
6、不要信任傳進來的環境變數。如果它們被接下來的命令(如TZ、PATH、IFS等)使用時,請檢查並重設為已知的值。無論在什麼情況下,最好的方式就是明確的設定自己需要的(如PATH只包含系統bin目錄,設定IFS為空白格定位器和換行)。
7、從已知的地方開始。在指令碼開始時,確切cd到已知目錄,這麼一來,接下來任何相對路徑名稱才能指到已知位置。確認cd操作成功:cd app-dir || exit 1
8、使用syslog(8)保留審計跟蹤。記錄引用的日期與時間、username等,參見logger(1)的使用手冊。如果沒有logger,可建立一個函數保留記錄檔:
複製代碼 代碼如下:
logger(){
printf "%s\n" "$*" >> /var/adm/logsysfile
}
logger "Run by user " $(id -un) "($USER) at " $(/bin/date)
9、當使用該輸入時,一定將使用者輸入引用起來。例如:"$1"與"$*",這麼做可以防止居心不良的使用者輸入超出範圍的計算與執行。
10、勿在使用者輸入上使用eval。甚至在引用使用者輸入之後,也不要使用eval將它交給shell再處理。如果使用者讀取了你的指令碼,發現你使用eval,就能很輕鬆的利用這個指令碼進行任何破壞。
11、引用萬用字元展開的結果。你可以將空格、分號、反斜線等放在檔案名稱裡,讓棘手的事情交給系統管理員處理。如果管理的指令碼未引用檔案名稱參數,此指令碼將會造成系統的問題。
12、檢查使用者輸入是否有meta字元。如果使用eval或$(...)裡的輸入,請檢查是否有像$或`這類的meta字元。
13、檢測你的代碼,並小心謹慎閱讀它。尋找是否有可被利用的漏洞與錯誤。把所有壞心眼的想法都考慮進去,小心研究你的代碼,試著找出破壞它的方式,再修正發現的問題。
14、留意競爭條件(race condition)攻擊者是不是可以在你指令碼裡的任兩個命令之間執行任意命令,這對安全性是否有危害?如果是,換個方式處理你的指令碼。
15、對符號性串連心存懷疑。在chmod檔案或是編輯檔案時,檢查它是否真的是一個檔案,而非串連到某個關鍵性系統檔案的符號性串連(利用[ -L file ] 或 [ -h file ]檢測file是否為一符號性串連。
16、找其他人重新檢查你的程式,看看是否有問題。
17、儘可能用setgid而不要用setuid。這些術語稍後討論,簡之就是使用setgid能將損害範圍限制在某個組內。
18、使用新的使用者而不是root。如果你必須使用setuid訪問一組檔案,請考慮建立一個新的使用者,非root的使用者做這件事並設定setuid給他。
19、儘可能限制使用setuid的代碼。儘可能讓setuid代碼減到最少。將它移到一個分開的程式,然後在大型指令碼裡需要時才引用它。無論如何,請做好代碼防護,好像指令碼可以被任何人於任何地方引用那樣。
20、一個安全shell的開場白:
複製代碼 代碼如下:
IFS=' \t\n' #之前幾篇見過很多次
unset -f unalias #確保unalias不是一個函數
\unalias -a #unset all aliases and quote unalias so it's not alias-expanded
unset -f command #確保調用的command不是以函數
#獲得可靠的路徑首碼,處理getconf停用情況。
#get a reliable path prefix,handling case where getconf is not available.
SYSPATH="$(command -p getconf PATH 2>/dev/null))"
if [[ -z "$SYSPATH" ]];then
SYSPATH="/usr/bin:/bin"
fi
PATH="$SYSPATH:$PATH"
這段代碼使用了許多非POSIX的擴充,需要注意。
該書最後給出了如何編寫自己的shell程式的manual,和unix的檔案和檔案系統的介紹。至此該書通讀完畢。