我听说代码,软件中总会存在漏洞。但是,我不明白为什么不可能拥有一个没有利用漏洞的软件。如果公司继续更新其软件,最终将没有漏洞,对吗?

评论

这取决于我们正在讨论的软件大小。如果它是一个装有0.20美元微控制器的小玩具,而所有软件所做的却都是使LED闪烁,那么可以。但是大多数软件要比这复杂得多。

“如果公司继续更新其软件,最终将没有漏洞”,因为他们不断添加新功能,删除旧功能或更改它们。每次发生这种情况,都有可能犯一个错误,从而增加了一个新漏洞。

从理论上讲,软件可以没有错误。大型,复杂的软件不太可能没有错误,但是如果您付出了足够的努力,就可以使其没有错误。
@marshalcraft该评论到底是什么意思? Turing-Completeness如何影响代码的可利用性?

@MonkeyZeus每个漏洞都是一个漏洞,但并非每个漏洞都是一个漏洞。

#1 楼

软件太复杂

这是迄今为止最重要的因素。即使您只是看Web应用程序之类的东西,代码库中的工作量也是巨大的。该代码与技术配合使用,这些技术的标准是几十年前编写的一页一页的页面,并且提供了大多数开发人员从未听说过的功能。

结合现代软件是基于事实构建的库,这些库是基于库构建的,这些库基于某些OS功能抽象出了一些低级库,而这些库又只是1990年代编写的其他OS功能的包装。
即使您排除操作系统方面的问题,对于一个人来说,它也太大了,无法完全理解,这会导致下一个问题:

随着时间的流逝,知识会丢失注射剂现已使用20年了。他们还在附近。为何如此?要考虑的一个因素是,公司内部的知识会随着时间的流逝而流失。您可能会有一两个高级开发人员,他们了解并关心安全性,确保他们的代码不容易受到SQL注入的攻击,但是这些高级开发人员最终将担任不同的职务,更换公司或退休。新人将取代他们的位置,他们可能和优秀的开发人员一样,但是他们不了解或不关心安全性。结果,他们可能不知道或不在乎问题,因此找不到他们。真的是学校关心的事情。我记得关于在Java中使用SQL的第一课,我的老师使用字符串串联将参数插入查询中。我告诉他那是不安全的,并因打扰课程而大吼大叫。班上所有的学生都知道串连接是必经之路-毕竟,这就是老师的方法,老师永远不会教错任何东西,对吗?

所有这些学生现在都将进入开发领域,并愉快地编写易于注入的SQL代码,因为没有人在乎。为什么没人在乎呢?因为

公司对“完美的代码”不感兴趣

这是一个大胆的声明,但这是事实。对于一家公司,他们关心投资和回报。他们“投资”开发人员的时间(这花了公司一定的钱),并且他们期望可以将其功能出售给客户。出售的功能包括:


软件现在可以使用更多的文件格式
该软件现在包括应用程序内购买的产品
软件看起来更好
软件可以让您外观更好
软件运行更快
软件无缝地集成到您的工作流程中

没有缺陷的公司无法向您出售产品。 “软件不易遭受XSS攻击”不是您可以销售的产品,因此也不是公司想要投资的产品。解决安全问题就像洗衣服一样-没有人付钱给您洗衣服,没有人称赞您这样做而且您可能仍然不想这样做,但是您仍然必须这样做。

还有最后一点:

这是什么意思,您无法确定代码中是否包含任何错误。您无法证明某些软件是安全的,因为您看不到还有多少错误。让我演示一下:

function Compare(string a, string b)
{
    if (a.Length != b.Length)
    {
        // If the length is not equal, we know the strings will not be equal
        return -1;
    }
    else
    {
        for(int i = 0; i < a.Length; i++)
        {
            if(a[i] != b[i])
            {
                // If one character mismatches, the string is not equal
                return -1;
            }
        }

        // Since no characters mismatched, the strings are equal
        return 0;
    }
}


此代码对您来说安全吗?您可能会这样认为。如果字符串相等,则返回0,否则返回-1。所以有什么问题?问题在于,如果一个部分使用恒定的机密,而另一部分使用攻击者控制的输入,那么攻击者可以衡量该功能完成所需的时间。如果前三个字符匹配,则所需时间要比没有字符匹配的时间长。

这意味着攻击者可以尝试各种输入并测量完成所需的时间。花费的时间越长,相同的连续字符越多。如果有足够的时间,攻击者最终可以找出秘密字符串是什么。这称为旁道攻击。

可以修复此错误吗?当然是。任何错误都可以修复。但是,此演示的目的是要表明不一定必须清晰可见错误,并且要修复它们,您需要了解它们,知道如何解决它们,并有动机这样做。

总结...

我知道这是一篇很长的文章,所以我不怪你跳到最后。快速的版本是,编写无漏洞利用的代码确实非常困难,并且软件越复杂,难度就成倍增加。您的软件使用的每种技术,无论是Web,XML还是其他东西,都为您的代码库提供了成千上万个额外的利用载体。此外,您的雇主甚至可能不在乎生成不受攻击的代码,而是在乎可以出售的功能。最后,您真的可以确定它是免费的吗?还是您只是在等待下一个大举动向公众开放?

评论


从理论上讲这是有可能的,但我不知道为什么您会声称tor或任何特定的比特币客户端是无漏洞利用的。例如,只看tor,就会发现很多错误。极短的简短版本是“没有足够复杂的软件没有错误。”

–MechMK1
19-10-20在21:24



@Zheer我们有时会在安全关键型开源代码中发现可怕的漏洞,这些漏洞是由十多年或更久以前由受人尊敬的专家精心编写的(因为该代码被认为是重要的安全方面),并且已经被许多人多次审查。这些年没有注意到该漏洞。因此,我们有证据表明,所有这些因素不足以拥有无漏洞代码。

– Peteris
19-10-21在9:06

@marshalcraft这是一个古老的Windows组件在漫长的时间里把人们搞砸的具体故事。此外,我从未提到Windows本身。我刚刚说过“ OS组件”。

–MechMK1
19-10-21在10:34

@marshalcraft运行了一段时间后,Google Nexus 7手机曾经变得非常慢。最终Google追踪到Linux内核本身存在27年的内存泄漏。不只是Windows。所有复杂的软件都具有漏洞。

–鸭鸭
19-10-21在13:58

@Zheer存在自动漏洞扫描程序,并且被使用了。但是,使用自动系统时,您会得到误报和误报-意味着您将获得有关非漏洞事物的报告,而不会获得有关缺陷事物的报告。请记住,人工智能不是万灵药

–MechMK1
19-10-21在14:45

#2 楼

汇编:与所有操作系统内核一样,seL4内核包含一些汇编代码,在本例中为340行ARM汇编。对于seL4,这主要涉及进入和退出内核以及直接的硬件访问。为证明起见,我们假设此代码正确无误。硬件:我们假设硬件正常工作。实际上,这意味着假定硬件不受篡改,并且可以按照规范工作。这也意味着它必须在其运行条件下运行。硬件管理:证明仅对基础硬件进行了最小限度的假设。它从缓存一致性,缓存着色和TLB(转换后备缓冲区)管理中抽象出来。该证明假设这些功能已在上述组装层中正确实现,并且硬件按公布的方式工作。该证明还假设特别是这三个硬件管理功能对内核的行为没有任何影响。引导代码:当前的证明是关于内核已正确加载到内存中并进入一致的最小初始状态之后的操作。这样就省去了大约1,200行代码,内核程序员通常会认为这是内核的一部分。虚拟内存:根据“正常”正式验证项目的标准,虚拟内存不需要被视为对此的假设证明。但是,保证的程度要低于我们根据第一原则进行推理的证明的其他部分。更详细地说,虚拟内存是内核用来保护自己免受用户程序和用户程序相互影响的硬件机制。此部分已完全验证。但是,虚拟内存会带来复杂性,因为它会影响内核本身访问内存的方式。汇编:与所有操作系统内核一样,seL4内核包含一些汇编代码,在本例中为340行ARM汇编。对于seL4,这主要涉及进入和退出内核以及直接的硬件访问。为证明起见,我们假设此代码正确无误。硬件:我们假设硬件正常工作。实际上,这意味着假定硬件不受篡改,并且可以按照规范工作。这也意味着它必须在其运行条件下运行。硬件管理:证明仅对基础硬件进行了最小限度的假设。它从缓存一致性,缓存着色和TLB(转换后备缓冲区)管理中抽象出来。该证明假设这些功能已在上述组装层中正确实现,并且硬件按公布的方式工作。该证明还假设特别是这三个硬件管理功能对内核的行为没有任何影响。引导代码:当前的证明是关于内核已正确加载到内存中并进入一致的最小初始状态之后的操作。这样就省去了大约1,200行代码,内核程序员通常会认为这是内核的一部分。虚拟内存:根据“正常”正式验证项目的标准,虚拟内存不需要被视为对此的假设证明。但是,保证的程度要低于我们根据第一原则进行推理的证明的其他部分。更详细地说,虚拟内存是内核用来保护自己免受用户程序和用户程序相互影响的硬件机制。此部分已完全验证。但是,虚拟内存会带来复杂性,因为它会影响内核本身访问内存的方式。我们的执行模型在内核执行时假设内存的某种标准行为,并且我们通过证明内核行为的必要条件来证明这一假设的合理性。关键是:您必须相信我们,我们具备了所有必要条件,而且条件正确。我们的机器检查证明并不能迫使我们在这一点上完整。简而言之,在本部分的证明中,与其他部分不同,存在人为错误的可能性。
汇编:与所有操作系统内核一样,seL4内核包含一些汇编代码,在本例中为340行ARM汇编。对于seL4,这主要涉及进入和退出内核以及直接的硬件访问。为证明起见,我们假设此代码正确无误。硬件:我们假设硬件正常工作。实际上,这意味着假定硬件不受篡改,并且可以按照规范工作。这也意味着它必须在其运行条件下运行。硬件管理:证明仅对基础硬件进行了最小限度的假设。它从缓存一致性,缓存着色和TLB(转换后备缓冲区)管理中抽象出来。该证明假设这些功能已在上述组装层中正确实现,并且硬件按公布的方式工作。该证明还假设特别是这三个硬件管理功能对内核的行为没有任何影响。引导代码:当前的证明是关于内核已正确加载到内存中并进入一致的最小初始状态之后的操作。这样就省去了大约1,200行代码,内核程序员通常会认为这是内核的一部分。虚拟内存:根据“正常”正式验证项目的标准,虚拟内存不需要被视为对此的假设证明。但是,保证的程度要低于我们根据第一原则进行推理的证明的其他部分。更详细地说,虚拟内存是内核用来保护自己免受用户程序和用户程序相互影响的硬件机制。此部分已完全验证。但是,虚拟内存会带来复杂性,因为它会影响内核本身访问内存的方式。我们的执行模型在内核执行时假设内存的某种标准行为,并且我们通过证明内核行为的必要条件来证明这一假设的合理性。关键是:您必须相信我们,我们具备了所有必要条件,而且条件正确。我们的机器检查证明并不能迫使我们在这一点上完整。简而言之,在本部分的证明中,与其他部分不同,存在人为错误的可能性。
汇编:与所有操作系统内核一样,seL4内核包含一些汇编代码,在本例中为340行ARM汇编。对于seL4,这主要涉及进入和退出内核以及直接的硬件访问。为证明起见,我们假设此代码正确无误。硬件:我们假设硬件正常工作。实际上,这意味着假定硬件不受篡改,并且可以按照规范工作。这也意味着它必须在其运行条件下运行。硬件管理:证明仅对基础硬件进行了最小限度的假设。它从缓存一致性,缓存着色和TLB(转换后备缓冲区)管理中抽象出来。该证明假设这些功能已在上述组装层中正确实现,并且硬件按公布的方式工作。该证明还假设特别是这三个硬件管理功能对内核的行为没有任何影响。引导代码:当前的证明是关于内核已正确加载到内存中并进入一致的最小初始状态之后的操作。这样就省去了大约1,200行代码,内核程序员通常会认为这是内核的一部分。虚拟内存:根据“正常”正式验证项目的标准,虚拟内存不需要被视为对此的假设证明。但是,保证的程度要低于我们根据第一原则进行推理的证明的其他部分。更详细地说,虚拟内存是内核用来保护自己免受用户程序和用户程序相互影响的硬件机制。此部分已完全验证。但是,虚拟内存会带来复杂性,因为它会影响内核本身访问内存的方式。我们的执行模型在内核执行时假设内存的某种标准行为,并且我们通过证明内核行为的必要条件来证明这一假设的合理性。关键是:您必须相信我们,我们具备了所有必要条件,而且条件正确。我们的机器检查证明并不能迫使我们在这一点上完整。简而言之,在本部分的证明中,与其他部分不同,存在人为错误的可能性。
在撰写本文时,现有的答案集中在编写无错误代码的困难以及为什么不可能做到这一点。†
但是想像一下是否有可能。这可能是多么棘手。那里有一款软件获得了“无错误”的称号:L4系列微内核的成员seL4。我们可以用它来查看兔子洞的走向。
seL4是一个微内核。它的独特之处在于,在2009年,事实证明它没有错误。这意味着他们使用了自动证明系统,以数学方式证明,如果代码是由符合标准的编译器编译的,则生成的二进制代码将完全按照该语言文档的说明进行操作。后来对此进行了增强,以对微内核的ARM二进制代码做出类似的断言:

seL4微内核的ARM版本的二进制代码正确实现了其抽象规范中描述的行为,仅此而已。此外,该规范和seL4二进制文件满足了称为完整性和机密性的经典安全属性。

太棒了!我们提供了一个非常简单的软件,证明它是正确的。接下来是什么?
好,seL4的人不是在骗我们。然后,他们立即指出此证明具有局限性,并列举了其中一些局限性。

...在声明正确性证明时,必须仔细考虑所有这些警告。
现在,我们必须对seL4团队表示赞赏。这样的证明是令人难以置信的建立信任的声明。但是它显示了当您开始采用“无bug”的想法时,兔子洞会去哪里。您永远不会真正获得“无错”。您只需开始认真考虑更大的bug类。
最终,您将遇到最有趣,最人性化的问题:您是否在使用正确的软件来完成工作? seL4提供了几个很好的保证。他们是您实际需要的吗? MechMK1的答案指出了对某些代码的定时攻击。 seL4的证据明确不包括针对这些内容的辩护。如果您担心此类计时攻击,则seL4不保证任何有关它们的信息。您使用了错误的工具。
如果您查看漏洞利用的历史,那么到处都是使用错误工具并被其烧死的团队。回应评论:答案实际上是在利用免费代码。但是,我认为证明代码没有错误的证据对于证明它没有漏洞利用是必要的。

评论


还要注意的是,所有这些证明都是为了确保所得二进制文件的行为100%与抽象规范匹配。因此,如果抽象规范存在一个错误-指定功能交互的某些意外结果导致了一些有趣的攻击-那么二进制文件也将拥有它。而且许多安全缺陷确实是规范或某些协议中的漏洞,而不是实现中的漏洞。

– Peteris
19-10-21在9:11

另请参阅CompCert,证明C编译器遵循C标准(没有此标准,您就无法真正保证C程序的正确性...)

– Giacomo Alzetta
19-10-21在12:18

基于硬件的安全性故障并非没有我们所希望的那样。众所周知,当前的示例包括行锤,熔毁和频谱。此外,通常不可能证明没有侧信道攻击。旁道攻击依赖于实施细节。不能保证证明涵盖了所有可能的副信道类别(诚然,在量子计算的情况下,这种保证在理论上可能是可行的,但实际上是不可能的)。

–布赖恩
19-10-21在13:01

@CGCampbell我认为“无bug”是低门槛。只有您没有漏洞,我们才能有意义地谈论免费利用。

–Cort Ammon
19-10-21在15:21

而且在许多情况下,“错误的工具”是C。甚至C的一位发明者也写过这样的话:“如果您的代码超过X SLOC,则您应该考虑使用Ada。” X是1500或15K-我不再需要检查这本书。如今,有几种语言比C语言更健壮,但人们仍然坚持使用恐龙。在“ C陷阱与陷阱”一书中,使用更好的语言几乎不可能描述三分之二的错误。

– WGroleau
19-10-21在16:35

#3 楼

您可以拥有高质量的代码,但是开发它的成本将大大提高。航天飞机软件经过精心开发和严格测试,开发出非常可靠的软件-但比PHP脚本昂贵得多。 。例如,Linux TCP / IP堆栈非常坚固,几乎没有安全性问题(尽管不幸的是,最近才出现)。其他具有高攻击风险的软件包括OpenSSH,远程桌面,VPN端点。开发人员通常会意识到其软件的重要性,因为它们通常会提供“安全边界”,尤其是在进行预身份验证攻击时,它们通常会做得更好,并且安全问题更少。软件不是很好开发。一个显着的例子是OpenSSL,它被广泛使用,但内部结构混乱,很容易引入诸如Heart Bleed之类的安全漏洞。已采取步骤解决此问题,例如LibreSSL。

CMS软件中也会发生类似的效果。例如,Word Press核心通常设计良好,几乎没有问题。但是插件的可变性要大得多,而经常被过时的插件就是此类网站被黑客入侵的方式。

Web浏览器是其中的前沿。数十亿台式机用户依靠其Web浏览器来确保安全,并阻止恶意软件进入其系统。但是它们还需要快速,支持所有最新功能,并且仍然能够处理数百万个旧站点。因此,尽管我们所有人都希望Web浏览器成为值得信赖的安全性边界,但目前并非如此。

当定制软件(通常是Web应用程序)时,与核心基础结构开发人员相比,从事这些软件开发的人员通常经验不足且缺乏安全意识。商业时标使他们无法采取非常详细和谨慎的方法。但这可以通过在小范围内包含经过严格编码和测试的安全关键代码的体系结构来帮助。非安全性至关重要的代码可以更快地开发。

安全性工具和测试(包括静态分析器,模糊器和笔测试)可以帮助所有开发。有些可以嵌入到自动CI管道中,而更成熟的安全部门已经可以做到这一点。安全漏洞少得多。创新技术为我们带来了许多机遇。

评论


您提到了航天飞机,这使我想起:阿波罗任务计算机的零除数错误几乎阻止了阿波罗11号登月。 (当故障发生时,它采取了一种保护算法来防止陀螺仪翻滚。)

–Cort Ammon
19-10-21在15:24

这是一个有趣的。当然,在健壮性和交付时间之间总是要取舍,如果我们要设计一种简单的Web表单,并且使用风险不高,那么我们就不会在测试和质量保证上花费很多。另一方面,以我的经验来看,如果给予更多的测试和质量保证,大多数项目都是不平凡的,几乎所有项目都会从长期成本中受益。我经常看到的问题是,许多软件项目都是在缺乏安全关键文化的情况下执行的,例如银行/电信公司。

–前哨
19-10-23在8:35

补充一下(讽刺的)幽默:航天飞机计划(于1960年代末和1970年代初开发)可能没有错误,但是太空“程序”本身充满了错误! (可怜的``挑战者''船员知道这一点... R.I.P)。

–德席尔瓦先生
19-10-23在15:20



#4 楼

是的...

正如其他人指出的那样,可以验证您的代码,并通过这种方式证明您的代码将按预期工作。证明时间安排和不确定性模型(例如网络交互)的困难是困难之一,而不是不可能。 Meltdown和Spectre的修补程序表明,甚至可以解决边信道定时攻击,并且可以解决。如果您无法验证代码,请不要将其视为无错误的代码。如果可以的话,那么您...就可以毫无错误地解决问题了。原始的,不能按预期方式释放数据,不能置于错误或异常状态等,请记住,单独的代码毫无用处。如果开发人员编写具有这种证明的代码,但在本身包含硬件漏洞的硬件上运行该代码,则软件的安全性将变得毫无意义。

考虑一个简单的功能,可以从内存中检索某些加密数据将其存储在CPU寄存器中,对该寄存器进行适当的转换以解密,处理和重新加密数据。请注意,在某些时候,未加密的数据在寄存器中。如果该CPU硬件的可用操作码可以使程序不破坏该CPU寄存器,并且与您经过验证的代码并行运行,则存在基于硬件的攻击。<​​br />
这是什么意思,最终,要拥有这样一个没有漏洞利用的软件,您首先需要证明您拥有没有漏洞利用的硬件。正如Meltdown和Spectre(以及许多其他例子)所展示的那样,常用的硬件只是没有通过该标记。即使是军事规格和太空规格的硬件也无法达到该指标。可以在军事和太空部署中使用的LEON系列处理器仅针对单事件翻转(SEU)和单事件瞬态(SET)进行了加固。这很棒,但是这意味着攻击者总是有可能将系统放置在具有足够辐射的环境中,从而引起足够的颠覆和瞬变,从而使硬件处于异常状态。更多但......

因此,对软件和硬件进行校对还不够。在检验硬件时,我们甚至必须考虑环境影响。如果我们将LEON4暴露在足以使外壳不堪重负的辐射下,或者在外壳中引起足够的感应辐射以使处理器不堪重负,我们仍然会造成像差。在这一点上,总系统(软件,硬件,环境)将非常复杂,无法完全正确地定义以尝试这种证明。

...所以,不是,不是真的。 br />
假设我们已经设计了一个RDBMS,我们对代码进行了验证,我们对硬件进行了验证,并且对环境进行了验证。在某个时候,我们终于遇到了任何安全链中的薄弱环节:

Idio ... er,用户。系统。 PFY-让我们更加慈善,并为他们授予标题“ JrOp” ... JrOp访问数据库,并且仅获得JrOp需要知道的数据,仅此而已。在光彩夺目的瞬间,只有JrOps可以鼓起勇气,我们的JrOp向同事倾诉,喃喃地说:“您看到User12358W刚刚上传了什么吗?看看这个!”

...最后的希望(并荒谬地击败它)...

但是,让我们说,我们想象着未来的假设,我们终于可以弄清楚人类的意识了。人类终于实现了对人类所有心理功能的科学和技术解释。让我们进一步说,这使我们甚至可以针对用户来证明我们的系统-系统中内置了适当的反馈系统,以确保我们的JrOp甚至不认为会泄露给JrOp。我们可以将元伦理学和人为操纵的问题留给哲学家-谈到哲学家... >“啊哈哈,” Pyrrhonic怀疑论者高兴地说。 “您已经假设某种形式的系统是正确的,例如ZF / ZFC,Peano,非幼稚的Set理论,经典命题逻辑。为什么?”

能给出什么答案?在Godel和Tarski之间,我们甚至无法正式定义真理(请参见Godel的不完全性定理和Tarski的不可定义性定理),因此即使是这样的断言,“好吧,我们选择它是因为使用与现实保持一致的系统似乎不错”只是一个没有根据的假设-这意味着我们的系统不受攻击的任何证明最终都是假设本身。

...所以,不是这样。通过将无缺陷的代码作为数学证明来编写,从而有可能编写无缺陷的代码,从而在技术上达到“无缺陷代码”的最高目标,这需要在无尘的情况下看代码。这样做有一定的价值-这是一个值得实现的目标(“但前提是要担心-”“大多数人都会这样做,对付Pyrrho”)。但是,永远不要让自己以为自己已经成功实现该目标而感到欣慰-如果这样做的话,请谦虚地将代码命名为“ HMS Titanic”。

评论


我想知道,“将其编写为数学证明”是什么意思?

–热尔
19-10-21在20:59



这可能意味着像使用Prolog这样的字面意思,或者从概念上来说像“编写证明然后根据证明和所选语言的规范编写代码”。

–LRWerewolf
19-10-21在21:06

我们可能必须降低一些要求,从“即使是原则上也无法利用的代码”减少到“难以利用的代码,以至于没有任何可想象的人会聪明地找出如何做的代码”。然后我们只需要担心AI ...

–杰里米·弗里斯纳(Jeremy Friesner)
19-10-22在3:34

这是正确的答案:是的,您可以花足够的精力编写完善的软件(阅读:$$$$$$$$$$$$$$$$),但这无关紧要,因为那不能保证安全性。 +1。

–杰瑞德·史密斯(Jared Smith)
19-10-22在19:32



@Zheer的意思是,例如,用Coq编写,这是一种纯函数式语言,可以证明数学断言,声明引理和实施证明。

– CPHPython
19-10-23在14:11

#5 楼

我想横向回答前面的问题。我不认为从理论上讲,没有错误的软件是不可能的,或者软件太复杂。我们还有其他复杂的系统,错误率要低得多。 />
很多问题,包括可利用的问题,都不是我们不知道如何正确编写代码的情况,只是正确的代码会更慢。或使用更多的内存。或更昂贵的写。软件中采用了许多快捷方式以加快速度或获得其他收益。其中一些捷径是利用漏洞的根源。

基本问题我们的编译器尚未被证明是安全的。通过自动化的依赖关系动态集成成百上千个小包装的图书馆系统,尤其是Node生态系统(现已由作曲家,货物和其他人复制),是一个巨大的安全噩梦。我必须使用72pt字体来显示大小。我们几乎所有的语言都包含根本上不安全的结构(Rust的思维方式说明了其中的几种)。我们的操作系统是建立在甚至有更多缺陷的更旧的系统上。对于复杂的系统。

结论

总而言之,就当今的软件世界而言,没有。除非我们谈论的是琐碎的或极其独立的(已经提到过的L4内核)代码,否则使用这些工具,思维方式和开发环境是无法利用无漏洞利用的代码的。从理论上讲,没有什么可以阻止我们从小模块构建软件,而每个小模块都可以被正式证明是正确的。没有什么能阻止我们对这些模型的关系,交互作用和接口进行建模并正式证明它们的正确性。

实际上,我们今天可以做到这一点,但是如果没有软件设计方面的根本进步,代码将会爬行,无法运行。

评论


您应该提供一些示例,说明这些与性能相关的问题的含义。这对我来说似乎是可疑的。当然-如果您在Coq中编写一些给定的算法来进行验证,那么运行起来通常会很慢。但这大部分归因于依赖类型的运行时处理。通常,可以将实际需要的程序部分提取为OCaml或Haskell,并且可以提供相当不错的性能。也许不如手动调整的C或Rust实现那么快,但是也没有“爬网,不能运行”。

–leftaround关于
19-10-22在11:33

@leftaroundabout我认为这是指例如通过启用的性能优化。 C中未定义的行为:编译器通过假设整数运算不会溢出,没有越界数组访问,没有空指针取消引用,没有未初始化的内存读取等来生成更快的代码。

–杰瑞德·史密斯(Jared Smith)
19-10-22在15:37

@JaredSmith也许就是Tom的意思,但是那一点绝对是无效的,除非在意义上“不要将C用于安全关键型应用程序”。例如。 Java避免了这些问题中的大多数,而不会影响性能,Rust和OCaml当然也可以。

–leftaround关于
19-10-22在15:41

@leftaround关于该分数我没有提出任何意见。

–杰瑞德·史密斯(Jared Smith)
19-10-22在15:47

我不是说一种特定的类型。英特尔CPU问题也是由过分的性能优化引起的。很多输入验证问题是由人们认为“不,这不会发生,我不需要检查”引起的,然后是,编译器优化,然后是代码中的快捷方式,然后是关于数据的假设,该清单继续存在。 。

–汤姆
19-10-23在5:26

#6 楼

可能吗?是。但是,不是您要寻找的软件。这可以包括忽略该输入。

唯一可以实现此目的的软件是Hello World以外的小型琐碎程序。在此没有任何利用:



print("Hello World")


,因为此代码将忽略所有输入,仅输出硬编码的字符串。

但是,此代码也可以为您完成0项有用的工作。

例如,只要您想连接到互联网并下载内容,便会正在下载您无法控制且可能是恶意的数据。当然,我们的下载软件对这些数据施加了很多限制来保护您,但无法防御您不知道的威胁角度。

评论


如果我编译此代码并使用输出重定向调用可执行文件,并且您的硬盘驱动器已完全装满,则可能会发生不良情况。

– gnasher729
19-10-21在21:26

@ gnasher729我认为您不能将这个问题归咎于“ hello world”程序-在这种情况下发生的任何不好的事情(即,比“磁盘空间不足”错误消息还严重)是由于一个错误在操作系统或操作系统的文件系统中。

–杰里米·弗里斯纳(Jeremy Friesner)
19-10-22在3:30



请注意,可以利用上面的代码,但无法利用您认为的地方。早在Unix被发明时,Ken Thompson开了个玩笑,把特洛伊木马引入了一个唯一的C编译器,如果任何程序截取了特定的输入,它将破坏Unix(请参阅他的开创性论文win.tue.nl/~aeb/ linux / hh / thompson / trust.html)。虽然确实通过利用编译器来“欺骗”,但所有利用都利用了程序源代码之外的东西:rowhammer利用了RAM的制造方式,CRIME利用了压缩数据的统计异常等。

– slebetman
19-10-22在7:07

@Zheer IMO,您将在使用硬件,而不是程序。


19-10-22在13:39



@ zheer per gloweye的评论,区别在于语义上不切实际。出于理智的考虑,无论我们多假装一次,都没有程序独立于其运行的硬件。或为此运行的软件(例如操作系统或虚拟机)。换句话说,是的。

–杰瑞德·史密斯(Jared Smith)
19-10-22在15:32



#7 楼

是的
我很惊讶没有人提到正式验证的名字(尽管Cort的回答中确实提到了经过正式验证的L4微内核)。
我个人对正式验证并不十分熟悉,所以我将指向该主题的Wikipedia页面上的一些相关内容;有关更多信息,请参考它。

在硬件和软件系统的上下文中,形式验证是证明或反证某个系统相对于某种形式规范或系统的预期算法的正确性的行为。 [1]
对软件程序的形式验证包括证明程序满足其行为的形式规范。 [...]
设计复杂性的增长增加了形式验证技术在硬件行业中的重要性。[6] [7]目前,大多数或所有领先的硬件公司都在使用形式验证,[8]但在软件行业的使用却仍在减少。[需要引用]这可能归因于硬件行业的更大需求,在该行业中,错误更大。具有商业意义。[需要引证]
截至2011年,已经正式验证了多种操作系统:NICTA的安全嵌入式L4微内核,由OK Labs以seL4的形式商业销售; [10]华东师范大学实时操作系统ORIENTAIS; [需要引用] Green Hills Software的Integrity操作系统; [需要引用]和SYSGO的PikeOS。[11] [12]
截至2016年,耶鲁大学和哥伦比亚大学教授Zhong Shao顾荣辉和顾荣辉为区块链开发了一种正式的验证协议,称为CertiKOS。[13]该程序是区块链世界中第一个形式验证的示例,并且形式验证的示例被明确用作安全程序。[14]
截至2017年,正式验证已通过网络的数学模型应用于大型计算机网络的设计[15],[16]作为新的网络技术类别的一部分,基于意图的网络[17]。提供正式验证解决方案的网络软件供应商包括Cisco [18],Forward Networks [19] [20]和Veriflow Systems。[21]
CompCert C编译器是经过正式验证的C编译器,实现了大多数ISOC。


评论


正确性不是没有错误。在我20年的经验中,90%的野外错误来自bug规范,而不是bug代码。因此,一个100%正确的程序仍然可能有问题

– slebetman
19-10-22在7:11

请记住,事情可以在实现中进行验证,但仍然存在无法预料的漏洞。量子密码术在数学上(通过所有已知物理学)是已知的,是坚不可摧的。但是,已经发现对实现的攻击。硬件完全按照指定的方式实施,规范背后的数学方法得到了验证……但是,仍然有可能遭受攻击:researchgate.net/publication/…

–贾罗德·克里斯特曼(Jarrod Christman)
19-10-22在13:35



我从橙皮书中提到“经过验证的设计”。但是我承认,正式验证看起来更加准确。

–peterh-恢复莫妮卡
19-10-23在7:27

+1,我想补充一点,您也可以使用正式的证明助手工具。

– CPHPython
19-10-23在15:01

尽管可以利用无漏洞利用软件,但绝对不能对其进行量化/验证。

–德席尔瓦先生
19-10-23在15:08

#8 楼

是的,如果系统的安全性在数学上得到证明。可信计算机系统评估标准(简称“橙皮书”)起源于1985年,这不是一个新主意。

我们已经验证了设计,因此命名为A1。这意味着从数学上证明了没有办法破坏系统。据我所知,没有完整的计算机系统具有这样的证明,但是某些系统(至少是VM / ESA内核)已得到部分证明。我们不知道,它们是来自哪里。例如,这样的数学模型会很好,并且适用于直接或间接假定没有办法窃听其内部TCP通信的系统。因此,有资格获得A1证书。在实践中,这样的系统很容易在受损的路由器上损坏。

通常,对程序进行自动化(或部分自动化)的正确性测试,包括自几十年前以来,它们的安全性测试一直是计算机科学领域的一个新兴领域。它产生了许多广受欢迎的出版物和博士学位。但这与25年前的实际广泛使用相距甚远。

评论


嗯,有一个C编译器,“使用机器辅助的数学证明对它进行了正式验证,可以避免错误编译问题”。我想这并不意味着没有错误,但是这是一大步。当然,按照当今的标准,C编译器可能很小(例如,它可能比我的彩电遥控器或手表中的软件小得多),但它并不琐碎,并且确实有用。

–彼得-恢复莫妮卡
19-10-23在14:41



@ PeterA.Schneider谢谢,很高兴知道!但是,这仅是编译器正确的证明,因此它不会从良好的源生成不良的二进制文件。它并不意味着(仅要求)使用它创建的所有软件都是正确的。

–peterh-恢复莫妮卡
19-10-23在16:55

确实 :-)。您使用它编译的软件可能像地狱般的虫子。但是我指的是编译器本身是一个经过验证的不重要的正确程序。

–彼得-恢复莫妮卡
19-10-23在17:12

@ PeterA.Schneider我想一种语言,更清楚地说,是任何语言的扩展,我们可以称之为证明。证明将是一种描述语言的语言,为什么代码正确。证明只能由人创建,但是可以通过算法验证证明的有效性(即证明是正确的)以及它与基础代码有关。可能有间断的副作用。例如,在实际的软件开发中,需要将代码+证明的复杂性/资源降至最低,而不仅仅是代码本身。

–peterh-恢复莫妮卡
19-10-25在8:30



@ PeterA.Schneider这样的证明+代码本质上是不可能编写错误代码的语言。不再需要自动化的测试,实际上什么也不需要,问题的唯一根源是不良的建模或任务陈述。

–peterh-恢复莫妮卡
19-10-25在8:33

#9 楼

在安全方面,我们想相信没有什么可以确保的,只有得到加强。

这是因为无论您尝试多少更新软件和应用程序,零日都存在。特别是如果您的软件值得一试。这意味着,尽管您的安全工程师团队可以解决此问题,但可以在该漏洞公开之前利用该软件。零天。

#10 楼

如果没有目前不存在的法规,这是有可能的,但是却不经济。完全按照描述执行-如果描述错误,那么可以称为漏洞利用。但是描述/规范中的错误相对很少见,即使它们确实是错误,也值得商bat。 ,因为我们的资源有限”。所有这些都可以通过以与seL4内核相同的方式开发硬件以及周围的软件和客户端软件来解决。 ,因为您将要使用的所有工具都可以证明是正确的,并且您只需要编写一些胶合代码。因此,对于一个小项目,需要证明正确的代码量将很小。现在,如果您想编写一个小的可证明正确的程序,则需要证明正确的代码量是巨大的,因为您基本上需要从头开始,而没有自计算机启动以来已经开发的任何可用工具。 。

如今,有些人呼吁使用压迫性工具,例如监视和审查,贸易封锁以及针对数字化的反击。软件和硬件制造商承担一定数量的责任(也称为责任),那么我们很快就会只有安全的软件。以完全安全的方式重建我们的软件生态系统所花费的时间要比最初创建它所花费的时间少得多。

评论


我们还必须丢弃所有现有软件(seL4和CompCert除外)。是的,确实如此。

–user253751
19-10-21在15:59

@immibis如果对不安全的软件进行惩罚,那可能或可能不经济。我确实在答案的最后一句话中暗示可能会得出结论。但这不太可能。引入突然的大额罚款将是愚蠢的,需要逐步过渡。因此,人们也可能会逐渐加强他们的软件。可证明的正确性不是编写安全软件的唯一方法,尽管它可能会使责任保险更加容易。

–没人
19-10-21在16:16

不管哪种方法在经济上最可行,我们都必须立即丢弃所有现有软件,因为它不安全。在编写新软件之前,它要回到铅笔和纸上。

–user253751
19-10-21在16:19



@immibis正如我在评论中重申的那样,显然这不是即时切换。这就是为什么也许我们想现在就开始,而不是在我们更加陷入困境而有人发动“网络战争”的时候。

–没人
19-10-21在17:15

至少在我的经验中,规范中的错误,模糊不清或其他问题非常普遍。尤其是在将来的某个时间点添加某些功能时,规范中通常不会充分探讨新功能和旧功能之间的交互。可以说“我们以书面形式实现”是很好的方法,但是如果这是一个实际问题,您仍然会在深夜/周末/假期中修复它。

–user3067860
19-10-21在21:26

#11 楼

当前,编写足够复杂的无错误代码非常昂贵。无限期地验证它实际上是否没有错误,或者验证程序是否没有错误,代价甚至更高。我认为没有人能够针对大多数商业软件的规模提供解决方案。

但是我认为某些程序可能存在错误,至少没有漏洞。例如,一个应该在完美的沙箱中运行的程序(例如浏览器),并且除了用户之外,不尝试与其他任何程序交互,或者至少没有任何书面记录表明其他程序应该信任该程序。如果出了问题,那是沙箱的漏洞,而不是程序本身的漏洞。

我们有多种方法可以设计仅在程序的多个不同设计版本都同意的情况下才能接受结果的系统。我们有办法使程序的各个部分成为无状态。通过使用这些方法,我们可以重新创建承诺。由于沙盒程序的复杂性有限,因此我认为,在遥远的将来,只要所有使用的算法都是可证明的,就有希望最终编写无漏洞利用的代码。不过,我不知道它是否会在经济上可行。

#12 楼

大多数答案都集中在启用漏洞的漏洞上。这是真的。但是,还有更根本的利用途径。

如果可以编程,就可以被黑。 ,甚至是恶意软件。
可编程性可以采取多种形式,其中有些并不十分明显。例如,文字处理程序或电子表格具有宏功能。此功能向用户提供序列。如果另外还有提供选择和重复的功能,突然之间它就非常可编程。

如果无法编程,用户将需要更大的灵活性。应用程序包最终将创建一个用户希望自动化其日常行为的环境。这种自动化有时采用脚本形式,例如Powershell或Python,但有时是通过诸如宏功能之类的东西来实现的,其中包括一些自动化的额外功能。当建造者容纳用户时,它突然变成了可编程系统。

评论


“如果可以编程,就可以被黑客入侵。”否。如果编程错误或规格不正确-可能会被黑客入侵。漏洞利用本身并不是一些神奇的生物。

–奥列格·沃尔科夫(Oleg V. Volkov)
19-10-22在18:29

如果您可以提出一种干净的方法将程序分为生产性组和适得其反的组,那么您是对的。我认为这样的干净分区是不可能的。

– Walter Mitty
19-10-23在7:11

#13 楼

只需考虑“开发”一栋坚不可摧的建筑……并考虑一些可能的方案和假设:


预算有限吗?永远是!预算较高的坏演员可能会购买进来的东西(例如在购买工具,贿赂建筑商中……)
总是存在无法控制的环境规模:一个地区正在泛滥,流星撞击了至关重要的安全性基础架构,技术进步,这是您无法计划的,...

通过这个例子,您可以让您的想象力疯狂。

现在,人们接受了这样一个事实,即建筑物通常更易于作为物理对象进行防御,很可能更简单,而且很少由具有像第三方软件库这样长的依赖链或难以确定来源的组件建造是。

评论


一个恰当的比喻。没有没有漏洞利用的复杂系统。无论是软件还是其他。

–马丁
19-10-23在7:55

#14 楼

从理论上讲,是的。

尽管可以利用无漏洞利用软件,但要实现这一点极其困难,如果可以编写一个软件来为您编程,从技术上讲,这是可能的。我听说有人试图做这样的事情,尽管它看起来比看起来要难,但是创建一个可以为您编程的机器人比看起来要困难。可以免费利用程序的另一种方法是,如果该软件经过数学验证。虽然,人造代码无法实现类似的目的,但是如果不需要人工输入,其他类型的编程也可以免费利用。

#15 楼

编写完美的代码就像制造一辆完美的汽车。我们也许能够制造出一辆完美的汽车,但仅适用于我们所处的时代。随着技术的发展,想法的共享以及更多人的头脑来解决问题,那么您可能会有更好的选择。

您的说法是正确的,如果一家公司继续开发软件,那么在某些时候它们将是无缺陷的。没错,但是随着时间的流逝,不同的技术会不断发展,您可以选择跟上技术的发展,还是跟上相同的完美旧代码库。

让我们以Facebook为例,因为它们是一个很大的群体,并且专注于单个产品。几年前,Facebook曾经将jquery库用于所有动态内容。这是一项最先进的技术,一切进展顺利,从未想过要取代它。但是要保持用户的参与度,他们需要变得更加动态。因此,随着facebook的增长,需要越来越多的动态功能,并意识到jquery无法满足他们的需求。

因为没有其他网站拥有如此众多的用户,所以没有机构真正了解对更新库的需求。因此,他们开始在自己的名为React的库上工作。随着时间的流逝,越来越多的人因为使用Facebook而开始使用互联网,因此很显然他们也被介绍给其他网站。现在其他网站也开始遇到Facebook所面临的问题,但幸运的是,现在他们有了React Library来满足他们的需求,而不是建立一个新的库。他们考虑使用facebook的React,以构建自己的解决方案来满足他们的特定需求。这将继续下去,并且永远不会有一个完美的代码库。

每当大的事物到达时,这就是自然法则,驱使更多的人去思考更大的事情,并且做得更好。越来越多的强大角色不断出现在《复仇者联盟》中。

因为时间是唯一的唯一实体,所以永远没有无限的时间。企业主和开发人员都是黑社会。 Triad off的代码可以是这样的:



要更优化/更快或更易于管理?
更多地关注安全性或获得更好的用户体验?
应该对新功能进行更多的测试还是按时发布新功能?

#16 楼

对于特定情况(程序),几乎。通常,对于特定情况,没有




您可以反复优化给定程序,直到大多数或所有已知形式的漏洞(即缓冲区溢出)消失为止,但是许多形式的漏洞都发生在源代码之外。例如,假设您编译了几乎或完美的程序。这将生成您分发的对象或可执行程序。在目标计算机中,它暴露于恶意软件下,这些恶意软件可能会进行修改,使得二进制代码(即插入跳转到恶意代码的过程)当然不在原始程序中。 >
现在或将来是否有一个程序能够验证任何程序的源代码是否存在漏洞?

有一点理论。成为无漏洞程序是程序的语义属性,而不是句法属性。语法属性可以形式化(因此可以通过形式方法检测),但是语义不能:

语义属性不是简单的语义属性。一个琐碎的语义属性是在所有程序中始终存在或始终不存在的语义属性。程序的一个众所周知的语义属性是“此程序将永远运行”(著名的图灵暂停问题),因为某些程序将永远运行,而其他程序则不会。都灵证明暂停问题是无法确定的,因此无法测试任何程序的暂停性质的正式方法。 。实际上,证明是基于以下事实:如果程序的非平凡语义属性是可确定的,则可以使用它来解决暂停程序,这是不可能的。

作为语义属性的另一个示例,请考虑属性“此程序有害”。当然,这是一种语义特性,因此,根据赖斯定理,无法建立正式的确定性恶意软件检测程序;

当然,由于其用于恶意软件检测,因此您可以使用启发式,人工智能,机器学习等方法来寻找漏洞的方法在代码中,但是不能存在形式,完善和确定性的代码。

#17 楼

软件测试(QA)的第一条规则:

'无法确认是否找到了最后一个错误'。

我从1980年开始编写代码(也是电子工程师),而我的软件都没有被利用,这并不意味着不可能,只是没有人使用过。银行系统(和类似“斯诺登”的系统)具有自动触发的警告/审计功能,可以记录未经授权的访问(我在类似系统上工作过)。

因此,是的,可以利用免费软件,但是您将如何量化/验证它?

最后,查找FCC(美国)规则:


FCC规则的第15部分,该规则管理无牌设备,
纳入了美国频谱政策的基本原则:
未经许可的设备必须接受任何来源的干扰,并且可能不会对任何许可的服务造成有害干扰


这意味着您的Wi-Fi信号是“可利用的”,这又意味着其上的软件是“可利用的”。

评论


“自动触发警告/审计以记录未经授权的访问”如何工作?如果您利用他们的系统,他们如何记录未经授权的访问?

–热尔
19-10-23在15:37

有两种类型的利用,授权的和未经授权的。授权人员可以在特定参数(时间/天/允许的菜单项等)内访问系统。未经授权的用户也属于该类别,并且无需登录即可执行某些操作。登录很容易,触发意味着脚本和/或数据库必须能够警告/控制用户/脚本的活动($$$) 。

–德席尔瓦先生
19-10-24在1:51

您的WiFi部分似乎与您的其余答案无关,似乎在逻辑上取得了巨大飞跃,并且对第15部分的理解有误; “无线电干扰”并不意味着“利用”。

– schroeder♦
19-10-25在12:08

@schroeder:我可以利用任何东西!我有技巧,这意味着那里还有其他人。问题是“利用自由软件”,由于容器可利用,因此无法完成!另外,我已经设计并制造了符合FCC的设备,因此我知道FCC规定和含义。

–德席尔瓦先生
19-10-25在13:57



而且您仍在阅读第15部分错误。而且您不断在逻辑上犯错误。没错,问题是“开发免费软件”而不是“无风险系统”。即使第15部分以某种方式表示“ WiFi漏洞”,“容器”中的漏洞也超出了问题的范围。

– schroeder♦
19-10-25在14:19