您可以为一个用户帐户指定多个密码吗?

您可以为一个用户帐户指定多个密码吗?

我想为一个帐户分配 2 个密码。我想知道的是 1)这可能吗?2)这对安全有何影响?

我之所以想这样做是因为我目前正忙于一些本地测试,我认为在某些特定情况下这会很方便。经过一番研究,我发现了一个叫做聚丙烯酰胺,但我正在努力寻找有关安装/配置如何工作的信息。

我运行的是 Ubuntu 12.04。

答案1

是的,虽然很不常见,但这绝对是可行的。

与其尝试自己实现它,因为/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.

以下是此类配置的一些技术和安全相关影响:

  • 用户帐户显然更容易受到攻击,尽管这里真正重要的是密码的质量和保护而不是密码的数量。
  • 大多数实用程序都假设用户只有一个密码,因此不允许用户单独更新其中一个密码。密码更改可能会导致用户拥有一个密码属性。
  • 如果目标是允许多人使用每个人自己的密码共享同一个帐户,则没有机制可以根据所使用的密码来识别谁实际登录。

答案2

我只是尝试在文件中为用户创建 2 个条目/etc/shadow,但没有成功。第一个条目是所使用的密码条目。

例子

创建了一个测试用户。

$ useradd -d /home/newuser newuser

将密码设置为“super123”:

$ passwd newuser

手动编辑/etc/shadow文件并创建第二个条目:

newuser:$6$....password #1...:15963:0:99999:7:::
newuser:$6$....password #2...:15963:0:99999:7:::

然后尝试使用 2 个密码登录该帐户。

su - newuser

第一个条目/etc/shadow是 get 使用的内容,第二个位置的条目永远不会起作用,如果你像这样翻转它们:

newuser:$6$....password #2...:15963:0:99999:7:::
newuser:$6$....password #1...:15963:0:99999:7:::

然后第二个密码有效,而第一个密码无效。

使用须藤

这种方法完全是一种黑客,我只会使用sudo,这就是sudo存在的部分原因。

您可以将此条目添加到您的 sudoers 文件 ( /etc/sudoers),这将允许用户 joe 执行以下操作:

joe ALL=(yourusername) ALL

答案3

如果你能做到这一点,你可能不应该这样做。

PAM 配置有些复杂,并且关于身份验证机制有一个不言而喻的事实:正确配置的集合是有限的,不安全配置的集合是无限的。这使得几乎可以肯定的是,如果你试图改变事情但又不确切知道自己在做什么,你就会把事情搞砸。

如果在安全性和“在某些特定情况下方便”之间进行选择,请选择前者。

答案4

您可以编写一个小型 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; }

您需要将该模块添加到 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

但无论如何,要格外小心 - 如果您没有完全理解您正在做的所有事情,请不要做任何这样的事情(例如,为什么success=3PAM 配置中有指令?)。

相关内容