使用 Go 根据 /etc/shadow 文件中的哈希密码验证密码
php小编子墨今天为大家介绍一种使用Go语言验证密码的方法,这个方法是基于读取/etc/shadow文件中的哈希密码进行验证的。在日常开发中,密码验证是一个非常重要的功能,而使用Go语言可以快速、高效地实现密码验证的功能。通过读取/etc/shadow文件中的哈希密码并进行比对,我们可以确保用户输入的密码与存储在系统中的密码一致。本文将详细介绍这个方法的实现过程,希望能对大家有所帮助。
问题内容
我目前在 /etc/shadow
文件中的密码格式类似于 $6$icnb6xpt8xjwc$ai9rq5hqpep.juts/tubhk/oi7so/s1aa.ihgbjhn12qmt5p44x5or86pso9/opbo4cmo0at4xumc0ycapo8 7/
(sha512
加密密码)。我需要做的是验证密码(用户提供的密码和当前的哈希密码)。我正在 go
上实现这个。
我试图实现这一目标的方法是,获取用户提供的密码,使用与 /etc/shadow
中相同的盐对其进行哈希处理,并检查它们是否相似或不同。如何生成相同的哈希值并验证密码?
下面是我正在做的粗略代码(根据 amadan 对编码的评论进行了更新)
// this is what is stored on /etc/shadow - a hashed string of "test" myPwd := "$6$IcnB6XpT8xjWC$AI9Rq5hqpEP.Juts/TUbHk/OI7sO/S1AA.ihgBjHN12QmT5p44X5or86PsO9/oPBO4cmo0At4XuMC0yCApo87/" // getting the salt salt := strings.Split(myPwd, "$")[2] encoding := base64.NewEncoding("./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz").WithPadding(base64.NoPadding) decodedSalt, err := encoding.DecodeString(salt) // user provided password myNewPwd := "test" newHashedPwd, err := hashPwd512(string(myNewPwd), string(decodedSalt)) // comparision if (newHashedPwd == myPwd) { // password is same, validate it } // What I'm expecting from this method is that for the same password stored in the /etc/shadow, // and the same salt, it should return (like the one in /etc/shadow file) // AI9Rq5hqpEP.Juts/TUbHk/OI7sO/S1AA.ihgBjHN12QmT5p44X5or86PsO9/oPBO4cmo0At4XuMC0yCApo87/ func hashPwd512(pwd string, salt string) (string, error) { hash := sha512.New() hash.Write([]byte(salt)) hash.Write([]byte(pwd)) encoding := base64.NewEncoding("./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz").WithPadding(base64.NoPadding) hashedPwd := encoding.EncodeToString(hash.Sum(nil)) return hashedPwd, nil }
注意:密码通过passwd
或chpasswd
设置/更改。
解决方法
sha512 是一种快速哈希。这对密码来说是不利的,因为当每次尝试几乎不需要花费任何成本时,暴力破解就变得非常容易。为了减慢速度,/etc/shadow
中的内容不仅仅是一个简单的 sha512 哈希值,而是 key拉伸适用于哈希算法运行数千次的情况。具体的密钥拉伸算法好像是这个。因此,crypto/sha512
只完成了所需任务的大约 1/5000(默认情况下)。
package main import ( "fmt" "strings" "github.com/gehirninc/crypt" _ "github.com/gehirninc/crypt/sha512_crypt" ) func main() { saltedpass := "$6$icnb6xpt8xjwc$ai9rq5hqpep.juts/tubhk/oi7so/s1aa.ihgbjhn12qmt5p44x5or86pso9/opbo4cmo0at4xumc0ycapo87/" fmt.println("original: ", saltedpass) // make new hash from scratch plainpass := "test" crypt := crypt.sha512.new() newsaltedpass, err := crypt.generate([]byte(plainpass), []byte(saltedpass)) if err != nil { panic(err) } fmt.println("generated:", newsaltedpass) // verify a password (correct) err = crypt.verify(saltedpass, []byte(plainpass)) fmt.println("verification error (correct password): ", err) // verify a password (incorrect) badpass := "fail" err = crypt.verify(saltedpass, []byte(badpass)) fmt.println("verification error (incorrect password):", err) }
由于您只需要验证,因此 verify
快捷方式就足够了(它会在幕后为您生成 generate
):
err = crypt.verify(saltedpass, []byte(plainpass)) if err == nil { fmt.println("fly, you fools!") } else { fmt.println("you shall not pass!") }
输出:
Original: $6$IcnB6XpT8xjWC$AI9Rq5hqpEP.Juts/TUbHk/OI7sO/S1AA.ihgBjHN12QmT5p44X5or86PsO9/oPBO4cmo0At4XuMC0yCApo87/ Generated: $6$IcnB6XpT8xjWC$AI9Rq5hqpEP.Juts/TUbHk/OI7sO/S1AA.ihgBjHN12QmT5p44X5or86PsO9/oPBO4cmo0At4XuMC0yCApo87/ Verification error (correct password): <nil> Verification error (incorrect password): hashed value is not the hash of the given password
注意:我相信我的评论是错误的。密码哈希本身就是通过这种编码进行编码的,但盐似乎是真正的盐(只是当它随机生成时,使用了该编码中的字符)。
该库还支持其他哈希函数,但您确实需要为每个函数进行导入才能注册它。您还可以看到,我没有费心从 saltedpass
中分离盐;这也是您不需要担心的事情。
但是,如果您出于某种原因确实想隔离盐,那么还要注意,从一开始就计算 $
并不是一个安全的想法,因为它将无法处理像 $6$rounds=77777$ 这样的条目例如,正确地短 $wuqyw2yr.hbnpjjrhpyd/ifiw05xdfeeyqomxixbkvr0g
。使用 strings.lastindex(saltedpass, "$") + 1
作为切入点。
以上是使用 Go 根据 /etc/shadow 文件中的哈希密码验证密码的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

Go语言中用于浮点数运算的库介绍在Go语言(也称为Golang)中,进行浮点数的加减乘除运算时,如何确保精度是�...

Go爬虫Colly中的Queue线程问题探讨在使用Go语言的Colly爬虫库时,开发者常常会遇到关于线程和请求队列的问题。�...

Go语言中字符串打印的区别:使用Println与string()函数的效果差异在Go...

Go语言中使用RedisStream实现消息队列时类型转换问题在使用Go语言与Redis...

GoLand中自定义结构体标签不显示怎么办?在使用GoLand进行Go语言开发时,很多开发者会遇到自定义结构体标签在�...

Go语言中结构体定义的两种方式:var与type关键字的差异Go语言在定义结构体时,经常会看到两种不同的写法:一�...

Go语言中哪些库是大公司开发或知名开源项目?在使用Go语言进行编程时,开发者常常会遇到一些常见的需求,�...
