我正在开发一个简单的命令行实用程序,它根据用户提供的密码加密/解密一个小文件。为了防止用户不得不在短时间内一遍又一遍地重新输入他/她的密码,我需要想出一个临时缓存这个密码(或派生的对称 key )的解决方案。这类似于 sudo
和 ssh-agent
等程序提供的功能。
到目前为止,我提出的解决方案是一个单独的类似守护进程的缓存程序,用于跟踪加密文件(尽管通常只有一个文件)和相应的 key 。文件由校验和 (SHA-256
) 标识,与加密客户端的通信通过 Unix 域套接字完成。
这是我在 Go 中的 net/rpc
包的帮助下创建的 RPC 服务的简化摘录:
type Checksum [ChecksumSize]byte
type SumKeyPair struct {
Sum Checksum
Key []byte
}
type KeyReply struct {
Key []byte
Available bool
}
type Cache map[Checksum][]byte
// Fetches key that corresponds with file checksum
func (c Cache) RequestKey(sum Checksum, reply *KeyReply) error {
reply.Key, reply.Available = c[sum]
return nil
}
// Adds or updates key that corresponds with file checksum
func (c Cache) SetKey(pair SumKeyPair, reply *bool) error {
_, *reply = c[pair.Sum]
c[pair.Sum] = pair.Key
return nil
}
RequestKey
将在用户每次想要解密文件时调用。 SetKey
将在每次提供正确的密码短语(带有更新的校验和)时被调用。
像这样在进程之间传输敏感数据是否安全?在 Unix 域套接字的情况下,保护是否类似于套接字文件的权限?如果有更好的方法,请告诉我。
两个准相关的问题:
- 什么是好的跨平台 IPC/缓存机制?我专注于 Linux,但支持 Windows 会更好。
- 我知道将密码/ key 保存在内存中并非 100% 安全,而是先有鸡还是先有蛋的问题。但是加密缓存的 key 会提高安全性吗?
最佳答案
如果您的目标是像 ssh-agent
或 gpg-agent
这样的守护进程,那么您可能不需要 RequestKey
操作。
那些其他代理的设计使得私钥永远不会发送到客户端进程。因此,ssh
不是从代理检索私钥以便执行基于质询的身份验证,而是将质询发送给代理,然后代理返回已签名的质询版本,准备发送到服务器。
简单来说,如果agent从来不通过IPC机制发送私钥,那么IPC机制就不能用来窥探私钥。
如果你想进一步提高代理的安全性,如果你在 Linux 上使用 UNIX 域套接字,你可以使用 SO_PEERCRED
套接字选项来查询你正在与之交谈的人的身份:
func getPeerCred(conn net.Conn) (*syscall.Ucred, error) {
file, err := conn.(*net.UnixConn).File()
if err != nil {
return nil, err
}
defer file.Close()
return syscall.GetsockoptUcred(int(file.Fd()), syscall.SOL_SOCKET, syscall.SO_PEERCRED)
}
返回的 Ucred
结构告诉您套接字另一端的进程、用户和组 ID。您可以使用此信息来决定是否要与他们交流。信息来自内核,客户端无法伪造。
关于security - 加密 key 的安全持久性和 IPC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20894291/