security - 如何安全地执行来自不受信任的第三方的确定性代码?

标签 security haskell monads deterministic purely-functional

我知道有几个问题与我的类似,但我的问题有点不同,我还没有找到正确的答案。

我知道运行来自不受信任来源的代码的一个简单方法是创建一个容器,一个资源有限的 jail ,然后等待超时;但我想要一个不同的解决方案。我需要结果是确定性的,也就是说,该代码不能有任何副作用,即使在隔离环境中也是如此。该代码将接收输入,并且必须始终根据该输入返回相同的输出。

我认为自然的方式是要求这段代码纯功能并且没有副作用。我想到了 Haskell 语言。是否有可能以某种方式禁用 Haskell(monad)中的副作用并运行纯功能性的代码?如何在 Haskell 中执行代码以禁用任何可能的副作用和各种 I/O?

一开始我并不介意代码是否进入无限循环并使用大量内存,但如果可以限制执行时间和内存使用,那就更好了。

最佳答案

开箱即用的 Haskell 无法为您提供所需的安全性。 unsafePerformIO 是一个明显的安全漏洞(但也存在其他漏洞)。

unsafePerformIO获取IO a类型的值并将其转换为a类型的值;这正是您不应该使用 IO 做的事情!它通过“欺骗”来做到这一点;如果需要结果值(a 类型),则 Hook 运行时系统以实际执行 IO 操作(IO a 类型)。从纯粹性的角度来看,它已经完全被破坏了;因为它允许您使用类型系统并为实际上执行任意副作用的计算提供非 IO 类型。但有时在高级用法中,您可以围绕内部使用杂质的事物构建纯接口(interface),这就是它的用途。

“礼貌”Haskell 不使用 unsafePerformIO 将重要的副作用1偷偷带入纯计算中,因此我们在推理纯代码时确实忽略了它。但是您正在谈论运行不受信任代码;你不能相信它是“礼貌的”。使用 unsafePerformIO 将副作用偷偷带入纯函数中正是对手为了越狱而将其放入代码中的东西。所以你不能忽略它(也不能忽略其他不安全的函数;GHC 提供的已知不安全函数的名称中会有 unsafe )。基本上,在这方面,Haskell 本质上并不比 C 更安全(事实上,有人可以使用 FFI 从 Haskell 调用任意 C 并将其称为纯 C!);它使用纯度作为一种语言功能来帮助开发人员编写代码,而不是作为一种安全功能来限制您不信任的代码。事实上,从这个意义上说,即使编译不受信任的 Haskell 代码实际上也不安全;编译时代码(例如使用 TemplateHaskell)可以执行任意副作用!

您可能对 Safe Haskell 感兴趣;这是 GHC 中的一个选择加入系统(通过语言扩展),它试图锁定 Haskell 的“后门”功能,以便(除其他保证外)您可以相信纯计算(没有 IO 类型)实际上是纯粹的。

警告:我从未真正尝试过使用 Safe Haskell,而且我无法判断它是否适合您的目的。我的理解是,您不能简单地打开LANGUAGE Safe并编译和运行任何旧代码。这并不那么安全。它是一个强化 Haskell 类型系统保证的工具,以便您可以将这些保证用作构建运行不受信任代码的沙箱所需的限制的一部分,但我不相信 Haskell 的类型系统担保本身就足够了。如果您想使用 Safe Haskell 来实现此目的,您绝对应该做进一步的研究。


1 当然,哪种副作用“重要”是个人喜好和上下文相关性的问题,上游代码可能并不总是同意您的观点。

关于security - 如何安全地执行来自不受信任的第三方的确定性代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73073339/

相关文章:

java - 加密发送到 MySQL DB 的 Android 应用程序数据

java - Java 字符串并非真正不可变的含义是什么?

lazy-evaluation - 懒惰评估及其效率的澄清

f# - 在 F# 的计算表达式中定义新关键字

java - 解码来自 X500Name 的 DER 编码值

java - 如果我使用和不使用 IvParameterSpec 初始化 AES 密码,有什么区别吗

unit-testing - Haskell 异常和单元测试

haskell - 为什么字节串的 Data.Binary 实例添加字节串的长度作为前缀

scala - 当我使用 "Reader monad"进行依赖注入(inject)时如何注入(inject)多个依赖项?

haskell - 如何修改或读取作为函数参数传递的可变向量?