use*_*215 16 ocaml garbage-collection haskell memory-management
我会做这样的事情(伪代码):
1. load sensitive encrypted data from file
2. decrypt the data
3. do something with the unencrypted data
4. override the data safely / securely (for example with random data)
Run Code Online (Sandbox Code Playgroud)
敏感数据在内存中保持原样(未加密)的时间应尽可能短。
不得以任何方式泄露明文数据。
A. 这样的程序可以用 Haskell 或 OCAML 编写吗?
B. 是否可以防止数据泄露,即被垃圾收集器在后台静默复制?
C. 能否在内存中正确覆盖纯数据?
据我所知,垃圾收集器 (GC) 可以在后台静默复制数据。我猜这是由分代 GC 算法完成的,但我不确定。
我知道如果攻击者设法在正确的时间/状态获取程序的内存,攻击者仍然有可能获得纯数据。我只是考虑这样做以提高安全性,因为我没有控制上下文(即操作系统、交换等)。
leh*_*ins 12
我已经在评论中提到了这一点,但我认为这是一个非常好的问题,值得回答。
已经存在ScrubbedBytes
具有以下属性的数据类型:
newAlignedPinnedByteArray#
,这意味着虽然新分配的MutableByteArray#
在你的代码中的任何地方被引用,但它不会被 GC,但它也不会被移动或复制。mkWeak#
并将终结器添加到新分配的内存中。这意味着每当您的代码中不再引用已清理的字节时,并且在 GC 释放内存之前,将调用清理器,将零写入内存。这个洗涤器有一个小问题。它不会被执行的可能性很小,特别是如果程序在 GC 应该清理内存之前退出。(查看有关弱指针的更多信息。)因此,我建议使用bracket
模式来实现它。以下是如何使用primitive
包完成它:
import Control.Exception
import Control.Monad.Primitive (RealWorld)
import qualified Data.Primitive.ByteArray as BA
withScrubbedMutableByteArray ::
Int -- ^ Number of bytes
-> (BA.MutableByteArray RealWorld -> IO a)
-- ^ Action to execute
-> IO a
withScrubbedMutableByteArray c f = do
mba <- BA.newPinnedByteArray c
f mba `finally` BA.setByteArray mba 0 c (0 :: Word8)
Run Code Online (Sandbox Code Playgroud)
使用finally
更安全的原因是因为您将有更强的保证将内存清零。例如,用户在正确的设置中按 Ctrl-C 不会阻止洗涤器运行。
在 OCaml 中,可以使用不受 GC 控制、从不复制、也从不检查的 Bigarray 轻松完成。您可以使用Unix.map_file加载它并使用 ocaml-struct很好地处理加载的数据(如果它是结构化的)。OCaml 广泛用于编写与安全相关的低级代码,请参阅Mirage项目(它有大量与加密相关的库)、ocaml-tls是 OCaml 中 TLS 协议的纯实现,以及使用 OCaml 作为TLS 协议的Project Everest目标语言。
在解密/加密和以其他方式处理秘密数据时,您应该小心,不要将其放入盒装类型中,包括字符串和 int64 整数。如果您查看mirage-crypto,您会发现所有算法都仅使用整数来实现,这些整数表示为立即数并且永远不会被 GC 触及。