CentOS密碼修改周期與登錄失敗處理
本文和等保聯系不是很密切,還是說一了些linux里細節一些的東西,所以有可能會浪費你生命中的好幾分鐘,同時我使用的是centos6。 一、密碼修改周期策略 首先貼上我的上一篇文章,和本篇有些關聯,大家有興趣可以去看一看:等保測評主機安全之centos之密碼長度。 在《等級測評師初級教程》里說/etc/login.defs是登錄程序的配置文件,同時說: 由于該文件里的配置對root用戶無效,如果/etc/shadow文件里有相同的選項,則以/etc/shadow里的設置為準,也就是說/etc/shadow的配置優先級高于/etc/login.defs。 說實話,我沒看懂這個因果關系,login.defs和shadow本質上就不是一個優先級的關系。 在shadow文件中,存有用戶的密碼和一系列的字段,其中包括對用戶的上一次修改密碼的日期、下一次需要修改密碼的日期等等,這些內容《等級測評師初級教程》說得比較清楚,我就直接截圖了:

其實這里面就說得很清楚了,對于“兩次修改口令間隔最少的天數”、“兩次修改口令間隔最多的天數”、“提前多少天警告用戶口令將過期”這三個字段,其實都是當你添加用戶時,從login.defs里讀取相關配置項,然后生成相應的值放置在shadow文件的相關字段中,而真正生效的實際上只是shadow文件存儲的這些字段。 所以login.defs能夠規定你添加的新用戶的相關策略,本質上就是一個“策略生成文件”或“默認策略生成文件”,里面的配置項本身并不能對當前用戶起什么效果,實際生效的策略比如密碼更換周期策略是由shadow相關字段值決定的。 所以書中所謂的/etc/shadow的配置優先級高于/etc/login.defs這句話,雖然結果是正確的,但是描述卻并不準確,因為本質就不是啥優先級的關系。 順便說一句,shadow第七字段和第八字段在login.defs文件中是沒有相關定義的,所以當然這兩個字段也不是從login.defs中讀取生成的,實際上是從/etc/defualt/useradd文件中讀取的,當然此文件還有一些其他的配置項,這里就不多說了。 其實,做兩個簡單的實驗即可證明,比如用chage命令修改某用戶的密碼更換策略,你會發現該用戶在shadow文件中的相關字段值也隨之發生改變。而你跑去修改login.defs中的密碼更換策略,你再用chage -l 用戶名去查詢某用戶的密碼更換策略或去查看shadow文件,你會發現是不會有什么變化的。 所以從這一點可以得知,如果較真的話,在進行檢查時,僅僅按照《等級測評師初級教程》的方法去查詢login.defs中的值那其實遠遠不夠的。 如果login.defs文件中的配置項符合要求,不代表現存用戶的密碼更換策略就符合要求(因為login.defs僅僅是策略生成文件,實際生效的策略在shadow那呢,兩者并不肯定相等,比如可以用chage命令對shadow進行修改),僅能代表這個系統新添加的用戶的密碼更換策略會符合要求。 所以實際應該連同shadow文件一起查看,嗯,有兩種方法,一種是直接去看shadow文件,不過這種格式稍微有點不友好。所以另一種就是用chage -l 用戶名的方式查看,內容容易理解: [root@centos01 ~]# chage -l rootLast password change : Mar 11, 2019Password expires : neverPassword inactive : neverAccount expires : neverMinimumnumberofdaysbetweenpasswordchange : 0Maximum numberofdaysbetweenpasswordchange : 99999Numberofdaysofwarningbeforepassword expires : 7
這里插句話,我實際上還遇上過另外一種情況,但這主要是對windows系統而言,就是windows系統策略中的密碼更換策略符合要求(密碼最長使用期限:40天),但是對方上次修改密碼卻在兩年前(用net user用戶名的命令可以看到)
因為,這個策略的強制性真正起效的時刻我猜應該是當你重新登錄這個賬戶時,也就是說,就算你一直沒改密碼,就算超過了期限,但只要你不退出登錄,你就根本不用搭理這個策略,你也并不會被直接強制登出。linux應該也是這樣,因為將密碼過期時間設置在以前的時間,也并不會把我強制登出。而對于承載業務的服務器,極有可能長時間不重啟。 而windows和linux不同之處在于,windows系統一般使用遠程桌面進行遠程管理時,它的默認設置為斷開會話但不會結束會話:
也就是說會話雖然斷開,但是這個用戶其實仍然處于登錄狀態,會話并沒有結束。用遠程桌面進行登錄時,你輸入用戶名、密碼只是為連接這個會話,而不是連接會話再在系統中進行登錄,所以可以實現長時間不改密碼。 linux則不同,用ssh連接,每次應該都要在系統中重新登錄,因為每次斷開會話后,會話實際就結束了。 二、登錄失敗處理功能 一般來說這個測評項有兩個內容,一個是賬戶登錄多次后進行鎖定,另一個就是長時間不進行活動就將之登出。 2.1. 賬戶鎖定策略 《等級測評師初級教程》讓我們直接去查找/etc/pam.d/system-auth,其實這是不夠全面的。
在等保測評主機安全之centos之密碼長度中我就有說過,除了比較老的centos版本,現在都是使用pam認證機制,pam認證機制大概是什么樣,看上面的文章即可。 具體到登錄驗證這一塊,linux至少有3種登錄方式: 1.本地tty登錄,這里是使用login命令,所以從而調用/etc/pam.d/login配置文件,最終調用底層的組件進行密碼驗證等; 2.本地圖形化界面,比如我用gdm,那么我在圖形化登錄界面時,就會調用/etc/pam.d/gdm配置文件; 3.ssh遠程登錄,就會調用/etc/pam.d/sshd配置文件。 然后再看看這三個配置文件的內容: /etc/pam.d/login #%PAM-1.0auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.soauth include system-authaccount required pam_nologin.soaccount include system-authpassword include system-auth# 3\. pam_selinux.so close should be the first session rule#session required pam_selinux.so closesession required pam_loginuid.sosession optional pam_console.so# 4\. pam_selinux.so open should only be followed by sessions to be executed in the user contextsession required pam_selinux.so opensession required pam_namespace.sosession optional pam_keyinit.so force revokesession include system-auth-session optional pam_ck_connector.sozz
/etc/pam.d/gdm
#%PAM-1.0auth [success=done ignore=ignore default=bad] pam_selinux_permit.soauth required pam_succeed_if.so user != root quietauth required pam_env.soauth substack system-authauth optional pam_gnome_keyring.soaccount required pam_nologin.soaccount include system-authpassword include system-authsession required pam_selinux.so closesession required pam_loginuid.sosession optional pam_console.sosession required pam_selinux.so opensession optional pam_keyinit.so force revokesession required pam_namespace.sosession optional pam_gnome_keyring.so auto_startsession include system-auth
/etc/pam.d/sshd
#%PAM-1.0auth required pam_sepermit.soauth include password-authaccount required pam_nologin.so
account include password-authpassword include password-auth# 3\. pam_selinux.so close should be the first session rulesession required pam_selinux.so closesession required pam_loginuid.so# 4\. pam_selinux.so open should only be followed by sessions to be executed in the user contextsession required pam_selinux.so open env_paramssession optional pam_keyinit.so force revokesession include password-auth
可以看到這三個配置文件使用include或substack又引用了其他的配置文件,具體下來則是:
1.login引用system-auth 2.gdm引用system-auth 3.sshd引用password-auth 所以,如果你要用pam_tally2組件(書里說的pam_tally組件過老,至少在centos6開始就不適用了)進行登錄鎖定策略設置,那么如果僅僅放置在system-auth文件中,實際上就只對本地tty和本地圖形化界面登錄方式進行了限制,雖然這也是一種防護,但是我想更多的人都是用ssh遠程連接的吧?要攻擊也是先從遠程連接下手吧? 如果別人都能跑到你的機房去多次嘗試登錄或者進行攻擊,那?????? 另外,這個策略語句究竟放置在配置文件中的哪個位置,會對是否生效造成影響,網上的回答往往就是說一句,把賬號鎖定策略放在最上面就沒了,雖然效果是有的,但是卻不知其所以然。 以system-auth文件進行舉例: #%PAM-1.0# 5\. This file is auto-generated.# 6\. User changes will be destroyed the next time authconfig is run.auth required pam_env.soauth sufficient pam_fprintd.soauth sufficient pam_unix.so nullok try_first_passauth requisite pam_succeed_if.so uid >= 500 quietauth required pam_deny.so
account required pam_unix.soaccount sufficient pam_localuser.soaccount sufficient pam_succeed_if.so uid < 500 quietaccount required pam_permit.so
password requisite pam_cracklib.so try_first_pass retry=300 type= minlen=8 minclass=4 enforce_for_rootpassword sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtokpassword required pam_deny.so
session optional pam_keyinit.so revokesession required pam_limits.sosession [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uidsession required pam_unix.so
說明pam的資料很多,我這里只是不準確的大致描述下。
auth、account、password、session,auth是一個標識符,說明要干的事情,auth處理登錄時驗證方面的事,account、password、session和登錄時驗證沒啥關系,比如password是處理更改密碼時的事情。 然后呢,調用配置文件里的組件時,是順序往下調用的,但是每次調用應該是一個類型一個類型的調用的(一共4個類型嘛),所以語句的順序應該指的是同一個類型的語句中的相對順序。 比如登錄驗證的時候,至少犯不著調用password這個類型吧?而具體調用的方式我猜應該是用字符串查找某個類型的行,比如我就要驗證功能的話,我就只找以auth開頭的行,而其余類型的行都不搭理。 所以如果你添加一個auth語句,你放在auth類型行的最后一行的下一行,和直接放在整個配置文件的最后一行應該沒啥區別,都是auth類型行的最后一行。 比如我這么改: #%PAM-1.0# 7\. This file is auto-generated.# 8\. User changes will be destroyed the next time authconfig is run.auth required pam_env.soauth sufficient pam_fprintd.so
account required pam_unix.soaccount sufficient pam_localuser.soaccount sufficient pam_succeed_if.so uid < 500 quietaccount required pam_permit.so
password requisite pam_cracklib.so try_first_pass retry=300 type= minlen=8 minclass=4 enforce_for_rootpassword sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtokpassword required pam_deny.so
session optional pam_keyinit.so revokesession required pam_limits.sosession [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uidsession required pam_unix.so
auth sufficient pam_unix.so nullok try_first_passauth requisite pam_succeed_if.so uid >= 500 quietauth required pam_deny.so
本地登錄功能沒有任何變化,完全正常運行。
好,扯遠了,那么pam_tally2的相關語句應該放置在哪才會有效果呢? 先把auth類型的行列出來: auth required pam_env.soauth sufficient pam_fprintd.soauth sufficient pam_unix.so nullok try_first_passauth requisite pam_succeed_if.so uid >= 500 quietauth required pam_deny.so
required大概意思就是,如果失敗了也繼續往下走,無論下面的語句成功與否,都會返回失敗值,一般是為了不告訴你具體失敗的原因。(如果成功,則應該繼續往下走)
sufficient的大概意思是,如果失敗了也繼續往下走,且本次失敗完全不影響最終結果。如果成功,且前面的required沒有過失敗,則立刻返回成功,不繼續往下走了。 特別注意的是,網上一般對sufficient的解釋很多都是錯的,變成了只要它成功了,無論前面是否有過失敗,都返回成功,比如:

實際上看man中的解釋,就能知道其錯誤處了: if such a module succeeds and no prior required module has failed the PAM framework returns success to the application or to the superior PAM stack immediately without calling any further modules in the stack. A failure of a sufficient module is ignored and processing of the PAM module stack continues unaffected. 好,pam_env好像和環境什么的有關,不用管。pam_fprintd好像是什么指紋驗證,而其控制標記是sufficient,所以失敗也無所謂。重要的是pam_unix,這個就是真正驗證你輸入的用戶名和密碼是否正確的組件了,很簡單的,如果它成功了,下面的語句一概不執行。 所以關鍵的地方來了,如果你想對登錄失敗次數過多的賬戶進行鎖定讓其不能登錄進去,那么你就得放在pam_unix.so的前面,否則只要輸入了正確的用戶名密碼就直接返回成功登入系統了,壓根不會執行pam_tally2…… 這下大家對語句放置點有個大概的把握了吧?網上資料雖多,但是很少有講明白的(至少我是真沒看得很明白,因為有些東西壓根就沒講),比如required和requisite如果執行成功,就一路往下走,而required如果執行失敗,也一路往下走。可到底走到哪是頭?是走到整個配置文件的終點?還是到哪?反正如果是跨越這4個類型走到配置文件的話,很多事根本沒法解釋,所以我只能認為是走到這個類型的最后一行 又回來,如果是本地tty登錄方式,那么login被調用,login中也引用了system-auth,這兩個都屬于被使用到的配置文件。所以對于本地tty登錄方式而言,把pam_tally2放在login文件里也是可以的,login文件如下: #%PAM-1.0auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.soauth include system-authaccount required pam_nologin.soaccount include system-authpassword include system-auth# 3\. pam_selinux.so close should be the first session rule#session required pam_selinux.so closesession required pam_loginuid.sosession optional pam_console.so# 4\. pam_selinux.so open should only be followed by sessions to be executed in the user contextsession required pam_selinux.so opensession required pam_namespace.sosession optional pam_keyinit.so force revokesession include system-auth-session optional pam_ck_connector.sozz
這里說明一下include,應該是僅僅引用include前面類型的system-auth中的類型行, 比如auth include system-auth,意思就是引用system-auth中的auth行。 否則的話,那不全亂套了,因為login文件中引用了system-auth4次!
同樣,substack應該也是這樣,它和include的有一點點區別,這里我就直接引用別人的資料吧:

注意,requesite一旦失敗就會直接讓結束流程,返回失敗,所以這里是用它舉例substack的作用,但并不僅僅只有它會這樣,(如果前面required語句沒有過失敗)一旦成功就會終止流程返回成功的sufficient也同樣會受到影響,不會影響到母棧。 所以,由于這里用的是include,而system-auth的pam_unix.so的控制符是sufficient,所以,pam_tally2應該放置于include語句之前才能起效果。 同樣的,對于gdm文件,用substack引用system-auth,所以pam_tally2放在substack之前還是之后都可以。