GO 存储密码

普通方案

目前用的最多的密码存储方案是将明文密码做单向哈希后存储,单向哈希算法有一个特征:无法通过哈希后的摘要(digest)恢复原始数据,这也是“单向”二字的来源。常用的单向哈希算法包括SHA-256, SHA-1, MD5等。

Go语言对这三种加密算法的实现如下所示:


//import "crypto/sha256"
h := sha256.New()
io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.")
fmt.Printf("% x", h.Sum(nil))

//import "crypto/sha1"
h := sha1.New()
io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.")
fmt.Printf("% x", h.Sum(nil))

//import "crypto/md5"
h := md5.New()
io.WriteString(h, "需要加密的密码")
fmt.Printf("%x", h.Sum(nil))

单向哈希有两个特性

  • 1)同一个密码进行单向哈希,得到的总是唯一确定的摘要。
  • 2)计算速度快。随着技术进步,一秒钟能够完成数十亿次单向哈希计算。

结合上面两个特点,考虑到多数人所使用的密码为常见的组合,攻击者可以将所有密码的常见组合进行单向哈希,得到一个摘要组合, 然后与数据库中的摘要进行比对即可获得对应的密码。这个摘要组合也被称为rainbow table

因此通过单向加密之后存储的数据,和明文存储没有多大区别。因此,一旦网站的数据库泄露,所有用户的密码本身就大白于天下。


进阶方案

现在安全性比较好的网站,都会用一种叫做“加盐”的方式来存储密码,也就是常说的 “salt”。他们通常的做法是,先将用户输入的密码进行一次MD5(或其它哈希算法)加密;将得到的 MD5 值前后加上一些只有管理员自己知道的随机串,再进行一次MD5加密。这个随机串中可以包括某些固定的串,也可以包括用户名(用来保证每个用户加密使用的密钥都不一样)。


//import "crypto/md5"
//假设用户名abc,密码123456
h := md5.New()
io.WriteString(h, "需要加密的密码")

//pwmd5等于e10adc3949ba59abbe56e057f20f883e
pwmd5 :=fmt.Sprintf("%x", h.Sum(nil))

//指定两个 salt: salt1 = @#$%   salt2 = ^&*()
salt1 := "@#$%"
salt2 := "^&*()"

//salt1+用户名+salt2+MD5拼接
io.WriteString(h, salt1)
io.WriteString(h, "abc")
io.WriteString(h, salt2)
io.WriteString(h, pwmd5)

last :=fmt.Sprintf("%x", h.Sum(nil))

 在两个salt没有泄露的情况下,黑客如果拿到的是最后这个加密串,就几乎不可能推算出原始的密码是什么了。


专家方案

上面的进阶方案在几年前也许是足够安全的方案,因为攻击者没有足够的资源建立这么多的rainbow table。 但是,时至今日,因为并行计算能力的提升,这种攻击已经完全可行。

怎么解决这个问题呢?只要时间与资源允许,没有破译不了的密码,所以方案是:故意增加密码计算所需耗费的资源和时间,使得任何人都不可获得足够的资源建立所需的rainbow table

这里推荐scrypt方案,scrypt是由著名的FreeBSD黑客Colin Percival为他的备份服务Tarsnap开发的

目前Go语言里面支持的库 https://github.com/golang/crypto/tree/master/scrypt

dk := scrypt.Key([]byte("some password"), []byte(salt), 16384, 8, 1, 32)

通过上面的方法可以获取唯一的相应的密码值,这是目前为止最难破解的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以帮你解决这个问题。首先,我们可以使用Go语言中的标准库crypto/md5来进行MD5加密,然后将加密后的密码存储在数据库中。具体的实现步骤如下: 1. 导入必要的包 ```go import ( "crypto/md5" "encoding/hex" "database/sql" _ "github.com/go-sql-driver/mysql" "fmt" ) ``` 2. 连接数据库 ```go db, err := sql.Open("mysql", "username:password@tcp(127.0.0.1:3306)/database_name") if err != nil { panic(err.Error()) } defer db.Close() ``` 3. 创建user表 ```go createTableSQL := `CREATE TABLE user ( id INT NOT NULL AUTO_INCREMENT, username VARCHAR(50), password VARCHAR(50), PRIMARY KEY (id) );` _, err = db.Exec(createTableSQL) if err != nil { panic(err.Error()) } ``` 4. 实现注册功能 ```go func register(username string, password string) error { stmt, err := db.Prepare("INSERT INTO user(username, password) VALUES(?, ?)") if err != nil { return err } defer stmt.Close() passwordHash := md5.Sum([]byte(password)) _, err = stmt.Exec(username, hex.EncodeToString(passwordHash[:])) if err != nil { return err } return nil } ``` 5. 实现登录功能 ```go func login(username string, password string) (bool, error) { rows, err := db.Query("SELECT password FROM user WHERE username = ?", username) if err != nil { return false, err } defer rows.Close() var dbPassword string if rows.Next() { err = rows.Scan(&dbPassword) if err != nil { return false, err } } else { return false, nil } passwordHash := md5.Sum([]byte(password)) if dbPassword == hex.EncodeToString(passwordHash[:]) { return true, nil } return false, nil } ``` 以上就是一个简单的密码登录并用MD5加密存储的实现方法。需要注意的是,在实际应用中,还需要对密码进行加盐等操作来提高安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值