【问题标题】:Using Go to generate hashed password strings suitable for `/etc/shadow`使用 Go 生成适合 `/etc/shadow` 的哈希密码字符串
【发布时间】:2020-09-17 05:40:56
【问题描述】:

我面前的任务是获取用户提供的纯文本字符串(即密码),并将其转换为可以插入到 /etc/shadow 中的哈希密码字符串,以便用户可以登录使用最初提供的密码来生成哈希。这是我们在系统管理员世界中一遍又一遍地(重新)解决的一个非常常见的问题。有无数的命令行工具可以做到这一点。

然而,在这种特定情况下,我的限制是我需要一个可以在多个上下文中使用的纯 Go 解决方案(cli 工具、api 等)。我的第一次尝试只是使用bcrypt 库。乍一看,它似乎拥有我需要的属性。它是纯 Go,使用起来超级简单(奖励),它生成的输出看起来就像我所追求的那样……但它没有用。使用此库产生的输出不能(例如)粘贴到/etc/shadow 作为用户密码,然后用户可以使用原始密码成功登录。

我只是想知道是否有人在他们的日常工作中遇到过这种需求并解决了它,谁愿意分享他们的经验和 (gasp) 代码?我主要想知道是否有针对此近似用例的库有人会推荐? (我的 google fu 可能只有 'rona)。

【问题讨论】:

  • 软件推荐与 StackOverflow 无关。但请尝试github.com/tredoe/osutil/tree/master/user/crypt,或谷歌“golang /etc/shadow”了解更多信息。或“/etc/shadow 格式”获取密码字段的详细信息。
  • 对我来说似乎是话题,这是一个关于 SO 的编码问题。
  • 加密类型取决于操作系统和版本。老系统用的是md5,早就坏掉了;永远不要使用这个。另见unix.stackexchange.com/questions/430141/…

标签: linux go hash passwords


【解决方案1】:

我在这里分享这个是因为我尝试的第一件事没有奏效,而且由于我公开询问,我觉得也公开分享解决方案是公平的。这是 a 解决方案,具体到我的情况。我并不是说它是 解决方案,或者没有更好的 解决方案(请张贴这些!)。对于我的具体情况,这就是我想出的... [编辑:请注意,用户 Marc 在我撰写此内容时建议在上面的评论中查看此库。谢谢你,Marc,我的 fu 感觉好多了]

如前所述,我的第一次尝试只是使用 bcrypt 库,但没有成功。经过仔细检查,我发现 bcrypt 仅以一种格式输出(即使用一种算法进行散列),这显然与 Linux 中的密码系统不兼容(至少不是我的特定发行版)。因此,虽然输出通常看起来应该是这样,但细节是:

bcrypt 给了我类似的东西:$2$10$sdfUILYhjd.HEdhjsdfgjhfdgjh.HEWjhndcjv

在第一个字段 ($2) 中,我的 Linux 发行版显然不支持类型 $2 (?)(广泛支持的是 $1, $5, $6(即 md5、sha256 和 sha512))。我似乎没有办法在 bcrypt go 库中指定不同的算法。因此,我寻求其他方法/解决方案。我得出的结论是:

package main

import (
    "fmt"
    "math/rand"
    "os"
    "time"
    "github.com/tredoe/osutil/user/crypt/sha512_crypt"
)

func encryptPassword(userPassword string) string {
    // Generate a random string for use in the salt
    const charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    seededRand := rand.New(rand.NewSource(time.Now().UnixNano()))
    s := make([]byte, 8)
    for i := range s {
        s[i] = charset[seededRand.Intn(len(charset))]
    }
    salt := []byte(fmt.Sprintf("$6$%s", s))
    // use salt to hash user-supplied password
    c := sha512_crypt.New()
    hash, err := c.Generate([]byte(userPassword), salt)
    if err != nil {
        fmt.Printf("error hashing user's supplied password: %s\n", err)
        os.Exit(1)
    }
    return string(hash)
}

此函数返回如下所示的字符串:

$6$tZeuYPZ3$3mj70WOprJj5ytFFzC8gUFYk7eymQvaR4lDg5C0WzwBAMupRAan7BaC6EAbL9Eiyi2GZR6PQIQQa.y6kZLqh6

您可以直接将其粘贴到/etc/shadow 或作为散列密码(kickstartcloud-init 等)提供给安装程序,然后开始您的业务。在我的例子中,我正在为一个应用程序编写一个库函数,我可以从命令行实用程序或从一个 api 服务调用该应用程序,该服务反过来将该散列字符串作为参数提供给 cloud-init。

HTH 其他人可能会在未来找到这个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-14
    • 2020-07-04
    • 2015-05-12
    • 1970-01-01
    • 2021-12-11
    • 2011-04-01
    • 2014-02-24
    相关资源
    最近更新 更多