我想为一个帐户分配 2 个密码。我想知道的是 1)这是可能的,以及 2)这有什么安全隐患?
我想这样做的原因是因为我目前正忙于一些本地测试,我认为在某些特定情况下会很方便。经过一番研究,我发现了一种叫做PAM 的东西,但我正在努力寻找有关安装/配置如何工作的信息。
我正在运行 Ubuntu 12.04。
jll*_*gre 19
是的,虽然很不常见,但这绝对是可行的。
与其尝试自己实现它,因为/etc/password
/etc/shadow
基于默认的身份验证方法没有提供此类配置,更简单的方法是将身份验证委托给已经支持用户多个密码的后端。
一个众所周知的一个是LDAP其userPassword
属性是根据多值RFC4519:
在“userPassword”属性中需要多个值的一个例子是这样的环境:每个月用户都需要使用由某个自动化系统生成的不同密码。在过渡期间,如期间的最后一天和第一天,可能需要在系统中允许连续两个期间的两个密码有效。
尽管有此 RFC,您可能需要更改大多数目录服务器实现上的密码策略配置,才能实际接受此设置。
在Linux方面,没什么者禁用做到这一点(这里命名一个帐号testuser
给予两者pass1
并pass2
为userPassword
属性值):
$ uname -a
Linux lx-vb 3.8.0-19-generic #29-Ubuntu SMP Wed Apr 17 18:16:28 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
$ grep VERSION /etc/os-release
VERSION="13.04, Raring Ringtail"
$ grep "^passwd" /etc/nsswitch.conf
passwd: files ldap
$ ldapsearch -LLL -h localhost -p 1389 -D "cn=directory manager" -w xxxxxxxx "uid=testuser" userPassword
dn: uid=testuser,ou=People,dc=example,dc=com
userPassword:: e1NTSEF9b2JWYXFDcjhNQmNJVXZXVHMzbE40SFlReStldC9XNFZ0NU4yRmc9PQ==
userPassword:: e1NTSEF9eDlnRGZ5b0NhKzNROTIzOTFha1NiR2VTMFJabjNKSWYyNkN3cUE9PQ==
$ grep testuser /etc/passwd
$ getent passwd testuser
testuser:*:12345:12345:ldap test user:/home/testuser:/bin/sh
$ sshpass -p pass1 ssh testuser@localhost id
uid=12345(testuser) gid=12345 groups=12345
$ sshpass -p pass2 ssh testuser@localhost id
uid=12345(testuser) gid=12345 groups=12345
$ sshpass -p pass3 ssh testuser@localhost id
Permission denied, please try again.
Run Code Online (Sandbox Code Playgroud)
以下是这种配置的一些技术和安全相关含义:
我只是尝试为/etc/shadow
文件中的用户创建 2 个条目,但没有成功。第一个条目是使用的密码条目。
创建了一个测试用户。
$ useradd -d /home/newuser newuser
Run Code Online (Sandbox Code Playgroud)
将密码设置为“super123”:
$ passwd newuser
Run Code Online (Sandbox Code Playgroud)
手动编辑/etc/shadow
文件并进行第二次输入:
newuser:$6$....password #1...:15963:0:99999:7:::
newuser:$6$....password #2...:15963:0:99999:7:::
Run Code Online (Sandbox Code Playgroud)
然后尝试使用 2 个密码使用该帐户登录。
su - newuser
Run Code Online (Sandbox Code Playgroud)
第一个条目/etc/shadow
是 get 使用的,第二个位置的条目永远不会工作,如果你像这样翻转它们:
newuser:$6$....password #2...:15963:0:99999:7:::
newuser:$6$....password #1...:15963:0:99999:7:::
Run Code Online (Sandbox Code Playgroud)
然后第二个密码有效,第一个密码无效。
这种方法完全是一种黑客行为,我只会使用sudo
,这部分是为什么sudo
存在。
您可以将此条目添加到您的 sudoers 文件 ( /etc/sudoers
) 中,这将允许用户 joe 像您一样执行任何操作:
joe ALL=(yourusername) ALL
Run Code Online (Sandbox Code Playgroud)
您可以编写一个小型 PAM 模块来接受帐户的多个不同(硬编码)密码。
这是此类模块的示例源代码:
// Compile with:
// gcc -fPIC -shared -o pam_multipass.so pam_multipass.c -lpam -lssl -lcrypto
// Install into /lib/security/ (or other location, depending on your distribution):
// sudo install --mode=0755 --owner=root --group=root pam_multipass.so /lib/security/pam_multipass.so
#define _GNU_SOURCE
#include <stdio.h>
#include <security/pam_modules.h>
#include <security/pam_ext.h>
#include <string.h>
#include <openssl/sha.h>
#define USERNAME "username"
#define PASSWORD_HASH_1 "xxxxxxxx"
#define PASSWORD_HASH_2 "xxxxxxxx"
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) {
const char *username;
char *password;
unsigned char result[SHA256_DIGEST_LENGTH];
char hexstring[65];
// Get the username
pam_get_user(pamh, &username, NULL);
if (strcmp(username, USERNAME) != 0) {
return PAM_IGNORE; // Not the user we're interested in
}
// Prompt for password
if (pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &password, "%s", "Password: ") != PAM_SUCCESS) {
fprintf(stderr, "pam_multipass pam_prompt failed\n");
return PAM_IGNORE;
}
if (pam_set_item(pamh, PAM_AUTHTOK, password) != PAM_SUCCESS) {
fprintf(stderr, "pam_multipass failed to set PAM_AUTHTOK\n");
}
SHA256((unsigned char *) password, strlen(password), result);
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
sprintf(hexstring + (i * 2), "%02x", result[i]);
}
// Compare with expected hash
if (
strcmp(hexstring, PASSWORD_HASH_1) == 0
|| strcmp(hexstring, PASSWORD_HASH_2) == 0
) {
return PAM_SUCCESS;
} else {
return PAM_IGNORE; // Allow other modules to authenticate
}
}
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { return PAM_IGNORE; }
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { return PAM_IGNORE; }
PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { return PAM_IGNORE; }
PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { return PAM_IGNORE; }
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) { return PAM_IGNORE; }
Run Code Online (Sandbox Code Playgroud)
您需要将该模块添加到 PAM 配置中,这可能很棘手。我以Arch Linux发行版为例,根据需要适配其他发行版:
# in /etc/pam.d/system-auth
auth required pam_faillock.so preauth
auth [success=3 default=ignore] pam_multipass.so # <--- our module
auth [success=2 default=ignore] pam_unix.so try_first_pass nullok
-auth [success=1 default=ignore] pam_systemd_home.so
auth [default=die] pam_faillock.so authfail
auth optional pam_permit.so
auth required pam_env.so
auth required pam_faillock.so authsucc
Run Code Online (Sandbox Code Playgroud)
但无论如何,要格外小心 - 如果您没有完全理解您正在做的所有事情,请不要做任何这样的事情(例如,为什么success=3
PAM 配置中有指令?)。
归档时间: |
|
查看次数: |
16702 次 |
最近记录: |