Linux 中的什么程序会在您登录时计算输入密码的哈希值?

JLC*_*JLC 12 security login authentication

如果我正确理解身份验证机制,当我们在登录提示中输入凭据时,会计算密码的哈希值,然后将该哈希值与存储在某处的哈希值进行比较,如果我没有记错的话,“某处”就是/etc/shadow. 如果匹配,则认证成功,否则认证失败。

我的问题是,什么程序,我的意思是哪个二进制文件,计算输入密码的哈希值?还是内核实现的?

Ste*_*ris 20

没有特定的二进制文件进行散列;这是通过库调用完成的crypt(3)。因此,理论上,任何程序(甚至perl脚本)都可以生成哈希值。例如

perl -e 'print crypt("hello","\$6\$0abcdef")'
$6$0abcdef$JhsHMeFo8zYQPa8/HDXGoMWZgIxiCJKu2BQqCGjkyh/NadMax6GiJWQOT5ZL7POkUzrwbvL/Yhbx9f8XtLr.F/
Run Code Online (Sandbox Code Playgroud)

您可以阅读有关此功能的更多信息man 3 crypt

现在,普通的 Unix 登录过程有点复杂。通常我们使用 PAM(“可插入身份验证模块”)堆栈。这与 NSS(“名称服务交换”)一起,在密码存储方式、位置以及身份验证方式方面提供了很大的灵活性。

使用 PAM 时,程序本身不会调用crypt(),它会调用 PAM 堆栈并决定使用什么。

一个非常常见的模式是使用pam_unixand 它将在pam_unix.so其中完成调用,并在其中完成crypt()与(或 LDAP 或任何地方)的比较。/etc/shadow

这种 PAM/NSS 组合非常强大,因为它意味着可以添加新的身份验证方法(例如加入 Active Directory 域),而无需每个程序都知道它;只需更新 PAM 配置,“神奇”就会发生。


Gil*_*il' 8

\n

当我们在登录提示中输入凭据时,会计算密码的哈希值,然后将该哈希值与存储在某处的哈希值进行比较,如果我没有记错的话,“某处”就是/etc/shadow.

\n
\n

这基本上是正确的(并且比网络上的许多简化解释更正确,做得很好)。更准确地说,数据流是:

\n
    \n
  1. 阅读一些配置文件。我假设它们会导致具有正常默认值的本地帐户的常见情况。此阶段的其他可能性可能导致查询网络帐户数据库,或执行非基于密码的身份验证,或者(但这并不常见)使用密码散列的不同位置执行基于密码的身份验证。
  2. \n
  3. 输入用户的密码P。(这可能会在下一步之后发生。)
  4. \n
  5. 找到包含所需用户名的行/etc/shadow并提取 \xe2\x80\x9cencrypted\xc2\xb9 密码\xe2\x80\x9d 字段。请注意,此步骤需要读取权限/etc/shadow
  6. \n
  7. 将影子字段拆分为两部分\xc2\xb2:配置+盐S和预期哈希H。将PS传递给crypt库函数\xc2\xb9,得到结果R。比较RH:如果相等则密码验证成功,否则密码验证失败。
  8. \n
  9. 如果存在非基于密码的方法,请继续进行用户身份验证。
  10. \n
  11. 如果认证成功,则登录用户,否则出错。
  12. \n
\n

在典型的嵌入式 Linux 系统上,所有这些步骤都发生在同一个程序中:login控制台登录、su提升sudo权限、dropbearSSH 登录等。步骤 1 可能完全省略,因为嵌入式系统通常没有任何运行时可配置性在此刻。该crypt函数的实现来自系统的标准库,例如musl。因此,执行计算的代码存储在类似的位置/lib/libc.so,而执行周围配置和数据库查找的代码则存储在/bin/login类似的位置。除了提供基本的输入输出原语(打开文件、读取文件等)之外,内核不参与身份验证。内核只会在身份验证后更直接地参与进来,以跟踪身份验证后进程的权限。/etc/shadow(如果身份验证程序不始终以 root 身份运行,则还可能涉及临时权限升级。)

\n

在典型的非嵌入式 Unix 系统上,此过程的大部分都分包给PAM库。PAM 由一个主库(/lib/libpam.so.0这里的 \xe2\x80\x94 和其他地方的确切路径取决于系统)以及许多辅助库和程序组成。我不会详细介绍,因为它们都是同一软件套件的一部分。身份验证程序调用PAM 库中的一系列函数来对用户进行身份验证,并决定成功身份验证(会话建立)后要执行的操作。我认为pam_authenticate是执行步骤 1 的部分以及步骤 3\xe2\x80\x935 的函数(我不确定,因为我不熟悉 PAM 的这一面)。

\n

使用 PAM,步骤 3\xe2\x80\x934(查找密码哈希并根据它验证密码)在用于传统基于密码的身份验证的 PAM 模块/lib/security/pam_unix.so中专门处理。该模块在执行身份验证的进程的上下文中运行,该进程可能无法以足够的权限运行来读取(但需要以足够的权限运行才能获取这些权限\xc2\xb3)。为了最大限度地减少可以访问密码哈希的代码量,这部分在专用程序中运行。该程序从 读取密码哈希值,调用该函数并验证其输出。pam_unix/etc/shadowunix_chkpwd/etc/shadowcrypt

\n

\xc2\xb9一个误导性的名称,因为密码是散列的,而不是加密的 \xe2\x80\x94 您无法 \xe2\x80\x9cdecrypt\xe2\x80\x9d 内容来查找原始密码。

\n

\xc2\xb2由于历史原因,界面有点奇怪。中的字段/etc/shadow包含 4 个部分:算法标识符、一些成本参数、盐字符串和预期输出字符串。算法标识符选择使用哪种密码哈希算法 \xe2\x80\x94 请注意,尽管顾名思义,这些都不是哈希算法。请参阅例如所有 Linux 发行版都使用相同的加密哈希函数吗?了解更多信息。成本参数取决于算法;较高的成本会使正常身份验证速度变慢,但如果攻击者设法检索哈希值,也会使破解密码变得更加困难。盐是唯一的,可以防止多帐户攻击(例如,尝试使用最弱密码进入员工的帐户,以在组织中获得立足点)。在内部,该crypt函数使用算法标识符来确定要调用哪个辅助函数,并且在某些系统上该辅助函数可以位于不同的库中。

\n

\xc2\xb3通常,程序(loginsu、 \xe2\x80\xa6)以 root 权限启动,并保留(至少是其自身的一部分)root 作为其保存的用户 ID,但将其有效用户 ID更改为专用系统用户(登录时)或调用用户(提升权限时)。这最大限度地降低了登录程序中存在安全漏洞的风险,该漏洞允许攻击者获得登录程序的部分控制权(例如读取文件),但无法执行任意代码。提升权限需要调用专用系统调用,例如seteuid.

\n


小智 3

负责计算输入密码哈希值的二进制文件通常是身份验证系统的一部分,并且不是由内核实现的。在大多数 Linux 发行版中,这是由名为cryptpasswd的程序处理的,并且使用的特定二进制文件可能因发行版而异。

以下是其工作原理的简单概述:

  1. 当用户登录或更改密码时,密码将传递到 crypt 或 passwd 实用程序。
  2. crypt 或 passwd 实用程序使用单向加密哈希函数计算输入密码的哈希值。使用的特定哈希函数可能有所不同,但通常基于 SHA-256 或 SHA-512 等算法。
  3. /etc/shadow然后将计算出的哈希值与相应用户的文件中存储的哈希值进行比较 。请注意,这意味着该实用程序需要具有读取影子文件的权限。
  4. 如果两个哈希值匹配,则身份验证成功,并且用户被授予访问权限。

散列和密码管理通常由用户空间程序处理,以确保灵活性以及与各种密码存储方案和散列算法的兼容性。内核仅负责用户空间身份验证实用程序之间的低级交互,并跟踪每个进程以什么用户身份运行。

  • 这在 20 年前可能是正确的,但如今人们必须允许 PAM 几乎得到普遍采用。 (3认同)
  • 也就是说,该程序被称为“crypt”是不正确的。好吧,在某些系统中可能是这样,但我从未听说过任何 Linux 中有一个名为“crypt”的独特程序,所以即使它存在,它也远非通用。当然,库函数“crypt()”是另一回事。 (2认同)
  • 我认为这个答案不正确,因为该程序名为“login”,而不是“passwd”或“crypt”。 (2认同)