PAM's Cracklib

Linux PAM之cracklib Module

前言

如何在Linux系统中限制密码长度的同时对密码的复杂程度也进行管理,最近发现有人的密码符合长度规则,但是却很简单很容易被猜出来,查了相关资料后发现了PAM中的pam_cracklib模块就是用来做密码复杂度检测的。

先简单的介绍一下PAM,PAM(Pluggable Authentication Modules )是由Sun提出的一种认证机制。它通过提供一些动态链接库和一套统一的API,将系统提供的服务和该服务的认证方式分开,使得系统管理员可以灵活地根据需要给不同的服务配置不同的认证方式而无需更改服务程序,同时也便于向系统中添加新的认证手段。 PAM模块是一种嵌入式模块,修改后即时生效。

pam的重要文件如下:

1
2
3
4
/usr/lib/libpam.so.*    ## PAM核心库
/etc/pam.conf ## PAM配置文件
/etc/pam.d/* ## PAM各个模块的配置文件
/lib/security/pam_*.so ## 可动态加载的PAM模块

PAM配置文件:

1
2
3
Module-type   Control-flag   Module-path   Arguments

模块类型 控制字符 模块路径 模块参数

Module-type:

    • auth:确定有关用户认证的两方面。第一,他确认用户就是他们自己,这通过应用程序提示用户输入密码或者其他正式身份的办法。第二,这类模块会赋予成员资格。
    • account:处理非认证级的账号管理。典型的用法是基于一天的不同时间来限制、允许访问某服务。限制当前可用的系统资源(最大用户数)或者限制特定用户—root只能从控制台登陆。
    • session:一系列有关动作,只在用户得到/失去服务时要做的事。这包括记录用户的登录/退出、挂载必要 的目录等。
    • password:设置密码。

Control-flag:

    • required:表示本模块必须返回成功才能通过认证,但是如果该模块返回失败的话,失败结果也不会立即 通知用户,而是要等到同一stack中的所有模块全部执行完毕再将失败结果返回给应用程序。可以认为是一个必要条件。
    • requisite:与required类似,该模块必须返回成功才能通过认证,但是一旦该模块返回失败,将不再执行 同一stack内的任何模块,而是直接将控制权返回给应用程序。是一个必要条件。注:Solaris不支持
    • sufficient:表明本模块返回成功已经足以通过身份认证的要求,不必再执行同一stack内的其它模块,但是 如果本模块返回失败的话可以忽略。可以认为是一个充分条件。
    • optional:表明本模块是可选的,它的成功与否一般不会对身份认证起关键作用,其返回值一般被忽略。
    • include:从字面就知道什么意思了。包含另外一个配置文件。

Module-path:

Debian的PAM module存放目录默认是在/lib/security。在各个模块的配置文件里,不用写绝对路径,直接写这个默认目录下面的模块名就可以了。当然,也可以写绝对路径。

    • Arguments:各个模块的参数都不一样,具体的要开发者的man手册。无效参数不会对结果有影响,但是会被日志记录 下来。首先,看看/lib/security有没有这个模块,再:man 模块名

cracklib模块

pam_cracklib是一个PAM模块,用来检查密码是否违反密码字典,这个验证模块可以通过插入password堆 栈,为特殊的应用提供可插入式密码强度性检测。 它的工作方式就是先提示用户输入密码,然后使用一个系统字典和一套规则来检测输入的密码是否不能满足强壮性要求。密码的强度检测分二次进行,第一次只是检测密 码是否是提供的对比字典中的一部分,如果检测结果是否定的,那么就会提供一些附加的检测来进一步检测其强度,例如检测新密码中的字符占旧密码字符的比例,密码的长度,所用字符大小写状况,以及是否使用了特殊字符等等。(libpam-cracklib)

下面是cracklib模块的一些参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
debug:将debug信息写入syslog

type=XXX:提示输入密码的文本内容。默认是"New UNIX password: " and "Retype UNIX password: ",可自定

retry=N:用户最多可以几次输入密码后报错。默认是1次。

difok=N:新密码有几个字符不能和旧密码相同,默认是5个。另外如果新密码有1/2的字符于旧不同,也会被接受。

diginore=N:默认当新密码有23个字符时,difok选项会被忽略。

minlen=N:最小密码长度。

dcredit=N:当N>=0时,N代表新密码最多可以有多少个阿拉伯数字。当N<0时,N代表新密码最少要有多少个阿拉伯数字。

ucredit=N:和dcredit差不多,但是这里说的是大写字母。

lcredit=N:和dcredit差不多,但是这里说的是小写字母。

ocredit=N:和dcredit差不多,但是这里说的是特殊字符。

use_authtok:在某个与密码相关的验证模块后使用此选项,例如pam_unix.so验证模块

pam_cracklib 模块式PAM配置接口的基本模块,在Debian系统中配置文件是/etc/pam.d/common-password 但是在Redhat系统中配置文件是 /etc/pam.d/system-auth 他的配置看起来像以下这样:

1
2
password required pam_cracklib.so retry=3 minlen=6 difok=3
password required pam_unix.so md5 use_authtok

第一行是pam_cracklib模块和设置的几个模块参数
第二行是pam_unix模块,MD5表示采用MD5加密
pam_cracklib可以记录用户使用的历史密码,并且不允许用户重复使用旧的密码,实际上存储用户旧密码的是通过pam_unix模块实现的。

    • 建立一个空文件用来存储旧密码/etc/security/opasswd,如果你没有建立文件却使用了历史密码记录功能的话,所有的密码更新都会失败,因为pam_unix模块会报错。

    opasswd就像/etc/shadow文件,因为他记录用户密码的哈希

1
2
3
:~$ touch /etc/security/opasswd
:~$ chown root:root /etc/security/opasswd
:~$ chmod 600 /etc/security/opasswd
    • 一旦建立了opasswd文件,就可以在pam_unix模块后面加上参数remember=N来开始记录旧密码,remember参数记录你想记录多少旧密码,他的最大值是400,如果你设置的值超过400会当做400来对待。
      例如:
      1
      2
      password required pam_cracklib.so retry=3 minlen=12 difok=4
      password required pam_unix.so md5 remember=12 use_authtok
      opasswd文件内容格式如下:
      1
      hal:1000:<n>:<hash1>,<hash2>,...,<hashn>
      ‘:’分割,第一列是用户名,第二列是用户ID,第三列是目前记录了该用户多少个旧密码,hashN是每次密码的MD5值,opasswd在某些系统安装PAM模块时会自动建立。

密码字典检查

pam_cracklib也可以检查用户设置的密码是不是违反系统内部的密码字典,在Debian系统中pam_cracklib的密码字典在/var/cache/cracklib目录下,而且每天晚上update-cracklib脚本会自动的rebuild密码字典。

/etc/login.defs文件设置密码过期时间等一系列参数,注意login.defs中设置的参数只有是用系统的useradd程序新建的一个用户时才会有login.defs中设置的属性,如果是用其他机器新建的用户,则没有以上属性,不过可以试用chage命令手动添加相关属性。

chage参数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
-m 密码可更改的最小天数。 为零时代表任何时候都可以更改密码。

-M 密码保持有效的最大天数。

-W 用户密码到期前,提前收到警告信息的天数。

-E 帐号到期的日期。过了这天,此帐号将不可用。

-d 上一次更改的日期

-i 停滞时期。如果一个密码已过期这些天,那么此帐号将不可用。

-l 例出当前的设置。由非特权用户来确定他们的密码或帐号何时过期。

在密码管理方面one time password(OTP)也很有效果,动态密码管理,有兴趣的同学可以研究一下。

查看原文