为什么美国政府不允许动态语言用于安全项目?


120

我知道有些人目前正在为美国军方项目(安全级别低,非战斗人力资源类型数据)进行工作。

项目代码的初始状态已提交给军方进行审查,然后他们通过某种安全分析器工具运行了该程序。它返回了代码中已知安全问题的报告,并要求进行更改,这些更改需要在交付最终产品之前实施。

需要解决的项目之一是删除一部分用Ruby编写的项目,因为它是一种动态语言。

不允许在安全设置中使用动态语言的背景/原因是什么?这是政府采用新技术的速度缓慢吗?还是与静态语言(ala C ++Java)相比,动态语言会带来额外的安全风险?


56
唯一可以确定的方法是您的熟人是否向雇主询问原因。但我可以冒险:静态类型检查是另一层有助于关键任务软件正确性的层。当然,它不会消除错误,但这是朝着正确方向迈出的一步:计算机正在为您完成一些工作。(是的,我知道这是圣战领土)。
Andres F.


75
您不希望用PHP + JavaScript编写导弹控制软件。
TulainsCórdova'13

16
HR数据不是 “低安全级别”。我希望一家公司尽可能确保我的工作和个人数据的安全。
gbjbaanb

5
@gbjbaanb我想OP意味着失去生命并不是这里最坏的情况。
Andres F.

Answers:


126

在动态语言中可以完成许多“整洁”的事情,可以将它们隐藏在代码的某些部分中,这些部分对于另一个程序员或审计人员而言,对于给定代码段的功能而言并不立即显而易见。

考虑irb(交互式红宝石外壳)中的以下顺序:

irb(main):001:0> "bar".foo
NoMethodError: undefined method `foo' for "bar":String
        from (irb):1
        from /usr/bin/irb:12:in `<main>'
irb(main):002:0> class String
irb(main):003:1> def foo
irb(main):004:2> "foobar!"
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> "bar".foo
=> "foobar!"

在那里发生的事情是我试图foo在String常量中调用该方法。这失败了。然后,我打开String类并定义了fooreturn 方法"foobar!",然后对其进行了调用。这工作了。

这被称为开放类,每当我想到用红宝石编写具有任何安全性或完整性的代码时,都会感到噩梦。当然,它可以使您快速地完成一些整洁的事情……但是我可以做到,这样每当有人存储一个字符串时,它就会将其存储到文件中,或者通过网络发送。重新定义String的这一点可以放在代码中的任何位置。

许多其他动态语言也可以完成类似的操作。Perl具有Tie :: Scalar,可以在幕后改变给定标量的工作方式(这更明显,并且需要您可以看到的特定命令,但是从其他地方传入的标量可能是个问题)。如果您有权访问Perl Cookbook,请查阅配方13.15-使用领带创建魔术变量。

由于这些因素(以及其他一些因素通常是动态语言的一部分),因此无法对代码中的安全性进行静态分析的许多方法都行不通。 Perl和Undecidability证明了这种情况,甚至指出了语法突出显示这样的琐碎问题(whatever / 25 ; # / ; die "this dies!";带来挑战,因为whatever可以在运行时将其定义为接受参数或不接受参数,从而完全击败了语法突出显示器或静态分析器)。


Ruby可以访问定义了闭包的环境,因此在Ruby中可能会变得更加有趣(请参阅Joshua Ballanco的YouTube: RubyConf 2011中的Ruby合理化)。MouseTheLuckyDogArs Technica的评论中使我意识到了该视频。

考虑以下代码:

def mal(&block)
    puts ">:)"
    block.call
    t = block.binding.eval('(self.methods - Object.methods).sample')
    block.binding.eval <<-END
        def #{t.to_s}
          raise 'MWHWAHAW!'
        end
    END
end

class Foo
    def bar
        puts "bar"
    end

    def qux
        mal do
            puts "qux"
        end
    end
end

f = Foo.new
f.bar
f.qux

f.bar
f.qux

这段代码是完全可见的,但是该mal方法可以在其他地方使用……当然,对于开放类,可以在其他地方重新定义该方法。

运行此代码:

〜/ $红宝石foo.rb 
酒吧
> :)
x
酒吧
b.rb:20:in'qux':MWHWAHAW!(RuntimeError)
    来自b.rb:30:in'
〜/ $红宝石foo.rb 
酒吧
> :)
x
b.rb:20:in'bar':MWHWAHAW!(RuntimeError)
    来自b.rb:29:in

在这段代码中,闭包能够访问该范围内该类中定义的所有方法和其他绑定。它选择了一个随机方法并重新定义它以引发异常。(请参阅Ruby中的Binding类以了解此对象可以访问的内容)

在此上下文中可以访问的变量,方法,自身值以及可能的迭代器块都将保留。

显示变量的重新定义的简短版本:

def mal(&block)
    block.call
    block.binding.eval('a = 43')
end

a = 42
puts a
mal do 
  puts 1
end
puts a

运行时会产生:

42
1个
43

这不仅仅是我上面提到的使静态分析变得不可能的开放类。上面展示的是,传递给其他地方的闭包带有定义所在的完整环境。这被称为一流环境(就像您可以传递函数一样,它们是一流函数,这是环境以及当时所有可用的绑定)。可以重新定义在闭包范围内定义的任何变量

是好是坏,抱怨或不抱怨红宝石(在某些情况下人们希望能够获得一种方法的环境(请参阅Perl中的Safe)),“为什么在政府项目中限制使用红宝石,这是一个问题”确实在上面链接的视频中得到了回答。

鉴于:

  1. Ruby允许人们从任何闭包中提取环境
  2. Ruby捕获闭包范围内的所有绑定
  3. Ruby将所有绑定保持为实时且可变的
  4. Ruby具有新的绑定,而不是旧的绑定(而不是克隆环境或禁止重新绑定)

有了这四个设计选择的含义,就不可能知道任何代码的作用。

有关更多信息,请参见Abstract Heresies博客。特别的帖子是关于Scheme的辩论。(与SO相关:Scheme为什么不支持一流的环境?

但是,随着时间的流逝,我开始意识到,一流的环境比我最初想象的要困难得多,功能也更少。在这一点上,我认为一流的环境充其量是无用的,而最坏的情况则是危险的。

我希望本节显示一流环境的危险方面,以及为什么会要求从提供的解决方案中删除Ruby。不仅Ruby是一种动态语言(如其他提及,答案,其他项目中允许使用其他动态语言),而且还有一些特定的问题使某些动态语言更加难以推理。


3
我不明白这一点。您提到了一个Perl类,该类允许更改标量的行为。但是,Perl被广泛使用,包括在安全环境中。仅在语言中具有这些功能并不意味着该语言无法使用。在Ruby的特定情况下,很可能是目标环境不支持Ruby。就个人而言,我从未见过可以在任何系统上使用Ruby,并且甚至不确定它是否在任何认可的软件列表中。
Thomas Owens

17
@ThomasOwens-我对这个答案的理解是,关键是"many approaches to static analysis of security in code doesn't work",因此被拒绝了,因为无法对其进行分析(至少由该小组)。我不知道是对的是正确的解释,还是什至是拒绝它的正当理由,我都不知道。
Bobson,

21
由于缺少批准软件列表中的信息,我只能猜测动态语言存在的困难。但是,我已经看到金融软件存在类似问题,并且支付卡行业检查失败,因为该语言无法针对安全性问题进行静态分析。我用动态语言演示了两个示例,其中语言的性质使它可以颠覆静态分析。我还指出了为什么即使从理论上讲也永远不可能是准确的。也许在某些地方允许使用perl,而在其他地方则不允许,我只能猜测原因。

2
您还可以使用许多其他语言(例如Obj-C,C,C ++)重新定义标准库函数。
Martin Wickman

12
嗯,.NET扩展方法与上述Ruby不同。它们只是创建一种简单的方式来键入静态类。他们实际上并没有向类添加方法。
格雷厄姆

50

假设评估仅是安全性,而不仅仅是接受扫描(也就是说,他们不接受Ruby是因为他们不想支持Ruby),那么:

安全分析工具通常在动态行为方面表现不佳。

例如:

通过诸如Veracode的程序运行任何用ASP.NET MVCEntity Framework等现代功能编写的.NET项目,并查看您在报告中收到的虚假肯定清单。

Veracode甚至将.NET 4核心库中的许多基本技术列为“不受支持的框架”,称为“不受支持的框架”或beta版,即使它们中的大多数在这一点上已经使用了几年。

如果您要与非常依赖此类工具的实体打交道,如果他们缺乏技术专长和资源,他们将几乎被迫考虑那些不安全的人,以手动评估项目并查看项目是否编写正确并安全。

在计算机系统通常无法控制任何危险或极其昂贵的民用业务中,缓解措施是您讨论误报,并且通常也接受这些误报。

在银行业务中,您仍然有可能出现误报的情况,但是您将花费更多的时间讨论每个项目的细节。这很快变得成本过高,您开始使用更传统的方法。

在军事,航空,重工业等领域,系统可以控制那些具有可怕故障模式的系统,因此它们可能对语言,编译器等有严格的规定。

组织通常还会针对他们所知道的最坏情况编写其安全策略,因此,即使您编写的内容微不足道,但如果是针对具有非常规系统的组织编写的,则默认情况下通常是将其保留为更高的标准,除非有人要求特定的例外。


4
那只是误报。真正令人担忧的是潜在的假阴性。
斯蒂芬·C

3
老实说,我对这些工具的经验通常很糟糕。大概是从1/200到1/1000的比率找到真正值得讨论的事物。另外,当我得到一个误报时,我知道在代码库或框架的成千上万的地方都使用了某种东西,并且它只在少数情况下才发现它,我对此并不充满信心。问题在于,除非您以诸如spec#之类的正式语言开始,否则在构建这些工具之一时,您正在有效地实施否定证明。
比尔

33

动态语言可用于国防和军事应用。我亲自在DoD应用程序中使用和交付了Perl和Python。我还看到了PHP和JavaScript的使用和部署。根据我的经验,我看到的大多数未编译代码都是shell脚本和Perl,因为所需的环境已被批准并安装在各种可能的目标系统上。

这些语言很可能是动态的,这并不是问题所在。这些语言的口译员必须经过批准才能在目标系统上使用。如果解释器未被批准使用(或者可能被批准,但是未部署在目标系统上),则该语言将无法使用。在安全系统上使用给定的解释器(或任何应用程序)需要任何数量的安全障碍:对源进行分析,针对目标环境从源进行编译的能力,对二进制文件的附加分析,确保与现有基础结构不发生冲突等。


32

我花了一些时间采访国防部(DOD),为F-16的MMU编写代码。在不违反任何保密规定的前提下:MMU是控制几乎所有F-16功能的计算机单元。(很明显)至关重要的是,在飞行过程中不会发生任何错误,例如运行时错误。系统执行实时计算操作同样重要。

由于这个和其他历史原因,该系统的所有代码都以ADA(一种静态的面向对象编程语言)编写或编译为ADA

由于Ada具有对安全性至关重要的支持功能,它现在不仅用于军事应用,而且还用于软件漏洞可能造成严重后果的商业项目,例如航空电子和空中交通管制,商业火箭(例如Ariane 4和5),卫星和其他空间系统,铁路运输和银行业务。例如,波音777中的电传飞行系统软件是用Ada编写的。

我讨厌引用太多,但这确实很好地解释了为什么将完全静态的语言(如ADA)用于这样的项目:

支持大量的编译时检查,以帮助避免在运行时使用某些其他语言才能检测到的错误,或者需要将显式检查添加到源代码中的错误。例如,该语法要求显式命名的块关闭,以防止由于结束令牌不匹配而导致错误。遵循强类型可以在编译时或在运行时检测许多常见的软件错误(错误的参数,范围违反,无效的引用,类型不匹配等)。由于并发是语言规范的一部分,因此在某些情况下,编译器可以检测到潜在的死锁。编译器通常还检查拼写错误的标识符,包的可见性,冗余声明等,并且可以提供警告和有关如何纠正错误的有用建议。

Ada还支持运行时检查,以防止访问未分配的内存,缓冲区溢出错误,范围冲突,一次性关闭错误,阵列访问错误和其他可检测到的错误。出于运行时效率的考虑,可以禁用这些检查,但是通常可以有效地进行编译。它还包括帮助程序验证的工具。由于这些原因,Ada被广泛用于关键系统中,其中任何异常都可能导致非常严重的后果,例如意外死亡,伤害或严重的财务损失。使用Ada的系统示例包括航空电子,铁路,银行,军事和太空技术。

Ada的动态内存管理是高级且类型安全的。Ada没有通用的(模糊的)“指针”;它也不隐式声明任何指针类型。相反,所有动态内存分配和释放都必须通过显式声明的访问类型进行。每种访问类型都有一个关联的存储池,用于处理内存管理的低级详细信息。程序员可以使用默认存储池,也可以定义新的存储池(这对于非统一内存访问尤为重要)。甚至可以声明几种不同的访问类型,它们都指定相同的类型,但使用不同的存储池。而且,该语言在编译时和运行时均提供了可访问性检查,以确保访问值不会超过它所指向的对象的类型。


3
“由于Ada的安全性至关重要的支持功能,现在它已用于[商业火箭](例如Ariane 4和5)。”当然,第一个Ariane 5由于软件错误而爆炸,因此没有灵丹妙药。
Andrew Marshall

5
@AndrewMarshall:“尽管该报告将软件错误确定为直接原因,但其他调查人员将这些原因视为系统设计失败和管理问题”-我严重怀疑使用其他语言(例如Java或C ++)编写的代码是否会火箭进入轨道。
MartinSchröder2014年

@MartinSchröder哦,我并不怀疑Ada在此应用程序中仍然可能优于其他应用程序,只是指出它不是万无一失的。另一种语言可能已经解决了Ada不可能实现的无数错误。
Andrew Marshall

13

国防部和美国国家航空航天局都有悠久的历史,编程失败使他们损失了数十亿美元。两家机构都接受了应该保护它们避免重复相同错误的流程。

Is this the government being slow to adopting new technologies?

这是一个误解-动态语言不是一种新技术,它们已经很老了。问题是,如果您曾经遇到过由动态语言(例如,弱类型/动态键入)引起的问题,而该问题使您损失了很多钱,那么您可以接受一项政策,以防止您再次犯同样的错误-例如禁止在敏感系统中使用动态语言。

动态语言通常会“吞噬”错误,并且最终会出现一些意外行为。这在敏感系统中非常危险。如果发生错误,您想尽快知道。

如果涉及安全性,则有必要查看实际用例。例如,我认为Ruby on Rails网页不会自动地比Java网页安全。


2
恕我直言,更多的错误被未被检测到的缓冲区溢出“吞噬”了,这恰恰是大多数动态语言最初不允许的……只是说
miraculixx 2014年

@miraculixx是的,确实有一个原因使得Java / C#和类似的语言比Ruby使用更多。他们是防御性的-他们检查一切。在C / C ++中,可以通过使用良好的编码标准来增强防御性。您还可以对所有内容执行检查。但是您能想象用ruby或javascript编写敏感的应用程序吗?隐藏错误的可能性很大。
苏珊(Sulthan)2015年

的确可以。我们可能同意,软件需要进行独立于编程语言的全面测试。为了避免回归,最好使用单元测试,BDD等人的方法进行自动化测试。假定采用专业方法(敏感的应用程序,对吗?),实现足够的测试覆盖范围是一个托管过程,并非偶然。因此,我怀疑C / C ++,Java在隐藏错误方面是否比ruby或javascript有优势。程序员技能?C ++可能更具技术性,而Java则令人怀疑,但几乎没有语言问题。技术含量更高!=产品质量。
miraculixx

6

我想通过描述Drupal的SA-CORE-2014-005来增加现有的答案,这是一个非常关键的漏洞,可以启用SQL注入并最终执行任意代码。它是由PHP的动态类型和宽松的运行时类型规则引起的。

此问题的修补程序的整体是:

-      foreach ($data as $i => $value) {
+      foreach (array_values($data) as $i => $value) {

此代码是旨在防止SQL注入的SQL抽象层的一部分。它需要一个带有命名参数的SQL查询,以及一个为每个命名参数提供值的关联数组。对于类似的情况WHERE x IN (val1, val2, val3),该值允许为数组,其中所有三个值都可以作为单个命名参数的单个数组值传递。

发生此漏洞是因为代码假定$iin $i => $value必须是该值的整数索引。它继续进行,并将此“索引”直接连接到SQL查询中作为参数名称的一部分,因为整数不需要任何转义,对吗?

对于Drupal不幸的是,PHP没有提供这样的保证。可以传入另一个键为字符串的关联数组,并且此循环将按原样愉快地将字符串键连接到查询中(请记住,代码认为它只能是整数)。

尽管有一些方法可以在静态类型的语言中产生类似的错误,但它们不太可能。一个好的开发人员在将$i其连接到查询之前会考虑可能发生的事情。使用静态类型的语言,必须非常容易执行,因为它$i必须是整数,并且在像这样的安全敏感代码中,肯定可以做到这一点。

此外,代码实际上在迭代项目之前检查该值是否为数组。这是导致该漏洞的失败的第二部分:关联数组和“正常”数组均对返回true is_array。虽然在C#中字典和数组都是IEnumerable,这也是事实,但很难构造将字典键与这样的数组索引进行混淆的代码,即使是有意的,更不用说偶然了。


2

代码库是否安全取决于代码编写方式,测试方式以及验证和监视开发与部署过程的方式。语言既不安全也不安全,这就是您编码的方式。

大多数安全事件是由于恶意输入(SQL注入,缓冲区溢出),病毒,Rootkit和木马引起的。没有语言可以保护您免受此伤害。

因此,禁止类的语言“不安全”不是正当的理由。

我怀疑有人出于某种原因(无论是否知情)决定禁止使用这些语言。过了一会儿,它变成了组织真理。对于某些项目,那时可能确实如此,但是控制文化并不热衷于更改决策(承认他们错了),而是更喜欢简单的规则。他们热衷于规章制度,并没有它们是否有意义或没有关系,它是避险才是最重要。

在控制文化中,这种情况一直存在。我每天或多或少看到它。这没有任何意义,但事实就是如此。如果您想阅读有关此高度相关主题的更多信息,我建议使用Schneider的书“ The Reengineering Alternative ”。这是Michael Sahoto / Agilitrix根据Schneider的书撰写文化图表在此处输入图片说明


18
-1对于安全关键型系统,有很多有效的技术原因可以选择一种语言(实时,静态键入,运行时检查)。您暗示其原因是100%的文化,我们与他们之间的文化和任意性,在这种情况下,IMO完全不正确。
2013年

8
“语言既不安全也不安全” –请参阅stackoverflow.com/a/14313277/602554。某些语言肯定比其他语言“更安全”。
2013年

2
更新了我的答案,也许是您的喜好。我仍然相信,系统的安全性取决于所编写的代码而不是所使用的语言,尽管某些语言可以避免某些问题(尽管可能会引入其他问题)。
马丁·威克曼

2
@MartinWickman:a)SQL / HTML注入和缓冲区溢出由某些类型系统解决-您对转义和未转义的输入有不同的类型,因此您知道应该以哪种方式处理。b)并非“安全项目”中的所有安全问题都必然意味着妥协。我不希望运行飞机的软件出现任何错误,即使这不是“安全”问题(即不能用来接管系统)也是如此。
Maciej Piechotka

5
-1为事实准确性问题。缓冲区溢出漏洞利用是高度针对C语言的问题。您从未听说过用不允许您在堆栈上分配字符串缓冲区的语言。而且,不难想象一个假设的SQL方言,其中不允许简单地使用而是必须使用Parameters 。用这种语言不可能进行SQL注入。所以是的,一种经过适当设计的语言可以保护您免受几种常见类型的攻击。
梅森惠勒2014年

2

据我所知,国防部的官方政策通常不禁止使用动态语言。

由国防部开发或采购的软件标准由国防信息系统局(DISA)颁布。他们的应用程序安全性-应用程序安全性和开发安全性技术实施指南(STIG)没有禁止任何特定语言。它没有提到Ruby,但是提到了类似动态的Perl和Python。它在各种主题的上下文中提及了它们(遵循既定的编码标准,避免了命令注入漏洞等)。

您可能看到的是一个过于严格的扫描工具(STIG中提到了几种不同的工具,每个工具可能都有自己对规则的解释)和/或对其输出的过于严格的解释。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.