我知道有些人目前正在为美国军方项目(安全级别低,非战斗人力资源类型数据)进行工作。
项目代码的初始状态已提交给军方进行审查,然后他们通过某种安全分析器工具运行了该程序。它返回了代码中已知安全问题的报告,并要求进行更改,这些更改需要在交付最终产品之前实施。
需要解决的项目之一是删除一部分用Ruby编写的项目,因为它是一种动态语言。
不允许在安全设置中使用动态语言的背景/原因是什么?这是政府采用新技术的速度缓慢吗?还是与静态语言(ala C ++或Java)相比,动态语言会带来额外的安全风险?
我知道有些人目前正在为美国军方项目(安全级别低,非战斗人力资源类型数据)进行工作。
项目代码的初始状态已提交给军方进行审查,然后他们通过某种安全分析器工具运行了该程序。它返回了代码中已知安全问题的报告,并要求进行更改,这些更改需要在交付最终产品之前实施。
需要解决的项目之一是删除一部分用Ruby编写的项目,因为它是一种动态语言。
不允许在安全设置中使用动态语言的背景/原因是什么?这是政府采用新技术的速度缓慢吗?还是与静态语言(ala C ++或Java)相比,动态语言会带来额外的安全风险?
Answers:
在动态语言中可以完成许多“整洁”的事情,可以将它们隐藏在代码的某些部分中,这些部分对于另一个程序员或审计人员而言,对于给定代码段的功能而言并不立即显而易见。
考虑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合理化)。MouseTheLuckyDog在Ars 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)),“为什么在政府项目中限制使用红宝石,这是一个问题”确实在上面链接的视频中得到了回答。
鉴于:
有了这四个设计选择的含义,就不可能知道任何代码的作用。
有关更多信息,请参见Abstract Heresies博客。特别的帖子是关于Scheme的辩论。(与SO相关:Scheme为什么不支持一流的环境?)
但是,随着时间的流逝,我开始意识到,一流的环境比我最初想象的要困难得多,功能也更少。在这一点上,我认为一流的环境充其量是无用的,而最坏的情况则是危险的。
我希望本节显示一流环境的危险方面,以及为什么会要求从提供的解决方案中删除Ruby。不仅Ruby是一种动态语言(如其他提及,答案,其他项目中允许使用其他动态语言),而且还有一些特定的问题使某些动态语言更加难以推理。
"many approaches to static analysis of security in code doesn't work",因此被拒绝了,因为无法对其进行分析(至少由该小组)。我不知道是对的是正确的解释,还是什至是拒绝它的正当理由,我都不知道。
假设评估仅是安全性,而不仅仅是接受扫描(也就是说,他们不接受Ruby是因为他们不想支持Ruby),那么:
安全分析工具通常在动态行为方面表现不佳。
例如:
通过诸如Veracode的程序运行任何用ASP.NET MVC和Entity Framework等现代功能编写的.NET项目,并查看您在报告中收到的虚假肯定清单。
Veracode甚至将.NET 4核心库中的许多基本技术列为“不受支持的框架”,称为“不受支持的框架”或beta版,即使它们中的大多数在这一点上已经使用了几年。
如果您要与非常依赖此类工具的实体打交道,如果他们缺乏技术专长和资源,他们将几乎被迫考虑那些不安全的人,以手动评估项目并查看项目是否编写正确并安全。
在计算机系统通常无法控制任何危险或极其昂贵的民用业务中,缓解措施是您讨论误报,并且通常也接受这些误报。
在银行业务中,您仍然有可能出现误报的情况,但是您将花费更多的时间讨论每个项目的细节。这很快变得成本过高,您开始使用更传统的方法。
在军事,航空,重工业等领域,系统可以控制那些具有可怕故障模式的系统,因此它们可能对语言,编译器等有严格的规定。
组织通常还会针对他们所知道的最坏情况编写其安全策略,因此,即使您编写的内容微不足道,但如果是针对具有非常规系统的组织编写的,则默认情况下通常是将其保留为更高的标准,除非有人要求特定的例外。
动态语言可用于国防和军事应用。我亲自在DoD应用程序中使用和交付了Perl和Python。我还看到了PHP和JavaScript的使用和部署。根据我的经验,我看到的大多数未编译代码都是shell脚本和Perl,因为所需的环境已被批准并安装在各种可能的目标系统上。
这些语言很可能是动态的,这并不是问题所在。这些语言的口译员必须经过批准才能在目标系统上使用。如果解释器未被批准使用(或者可能被批准,但是未部署在目标系统上),则该语言将无法使用。在安全系统上使用给定的解释器(或任何应用程序)需要任何数量的安全障碍:对源进行分析,针对目标环境从源进行编译的能力,对二进制文件的附加分析,确保与现有基础结构不发生冲突等。
我花了一些时间采访国防部(DOD),为F-16的MMU编写代码。在不违反任何保密规定的前提下:MMU是控制几乎所有F-16功能的计算机单元。(很明显)至关重要的是,在飞行过程中不会发生任何错误,例如运行时错误。系统执行实时计算操作同样重要。
由于这个和其他历史原因,该系统的所有代码都以ADA(一种静态的面向对象编程语言)编写或编译为ADA。
由于Ada具有对安全性至关重要的支持功能,它现在不仅用于军事应用,而且还用于软件漏洞可能造成严重后果的商业项目,例如航空电子和空中交通管制,商业火箭(例如Ariane 4和5),卫星和其他空间系统,铁路运输和银行业务。例如,波音777中的电传飞行系统软件是用Ada编写的。
我讨厌引用太多,但这确实很好地解释了为什么将完全静态的语言(如ADA)用于这样的项目:
支持大量的编译时检查,以帮助避免在运行时使用某些其他语言才能检测到的错误,或者需要将显式检查添加到源代码中的错误。例如,该语法要求显式命名的块关闭,以防止由于结束令牌不匹配而导致错误。遵循强类型可以在编译时或在运行时检测许多常见的软件错误(错误的参数,范围违反,无效的引用,类型不匹配等)。由于并发是语言规范的一部分,因此在某些情况下,编译器可以检测到潜在的死锁。编译器通常还检查拼写错误的标识符,包的可见性,冗余声明等,并且可以提供警告和有关如何纠正错误的有用建议。
Ada还支持运行时检查,以防止访问未分配的内存,缓冲区溢出错误,范围冲突,一次性关闭错误,阵列访问错误和其他可检测到的错误。出于运行时效率的考虑,可以禁用这些检查,但是通常可以有效地进行编译。它还包括帮助程序验证的工具。由于这些原因,Ada被广泛用于关键系统中,其中任何异常都可能导致非常严重的后果,例如意外死亡,伤害或严重的财务损失。使用Ada的系统示例包括航空电子,铁路,银行,军事和太空技术。
Ada的动态内存管理是高级且类型安全的。Ada没有通用的(模糊的)“指针”;它也不隐式声明任何指针类型。相反,所有动态内存分配和释放都必须通过显式声明的访问类型进行。每种访问类型都有一个关联的存储池,用于处理内存管理的低级详细信息。程序员可以使用默认存储池,也可以定义新的存储池(这对于非统一内存访问尤为重要)。甚至可以声明几种不同的访问类型,它们都指定相同的类型,但使用不同的存储池。而且,该语言在编译时和运行时均提供了可访问性检查,以确保访问值不会超过它所指向的对象的类型。
国防部和美国国家航空航天局都有悠久的历史,编程失败使他们损失了数十亿美元。两家机构都接受了应该保护它们避免重复相同错误的流程。
Is this the government being slow to adopting new technologies?
这是一个误解-动态语言不是一种新技术,它们已经很老了。问题是,如果您曾经遇到过由动态语言(例如,弱类型/动态键入)引起的问题,而该问题使您损失了很多钱,那么您可以接受一项政策,以防止您再次犯同样的错误-例如禁止在敏感系统中使用动态语言。
动态语言通常会“吞噬”错误,并且最终会出现一些意外行为。这在敏感系统中非常危险。如果发生错误,您想尽快知道。
如果涉及安全性,则有必要查看实际用例。例如,我认为Ruby on Rails网页不会自动地比Java网页安全。
我想通过描述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,这也是事实,但很难构造将字典键与这样的数组索引进行混淆的代码,即使是有意的,更不用说偶然了。
代码库是否安全取决于代码编写方式,测试方式以及验证和监视开发与部署过程的方式。语言既不安全也不安全,这就是您编码的方式。
大多数安全事件是由于恶意输入(SQL注入,缓冲区溢出),病毒,Rootkit和木马引起的。没有语言可以保护您免受此伤害。
因此,禁止类的语言“不安全”不是正当的理由。
我怀疑有人出于某种原因(无论是否知情)决定禁止使用这些语言。过了一会儿,它变成了组织真理。对于某些项目,那时可能确实如此,但是控制文化并不热衷于更改决策(承认他们错了),而是更喜欢简单的规则。他们热衷于规章制度,并没有它们是否有意义或没有关系,它是避险才是最重要。
在控制文化中,这种情况一直存在。我每天或多或少看到它。这没有任何意义,但事实就是如此。如果您想阅读有关此高度相关主题的更多信息,我建议使用Schneider的书“ The Reengineering Alternative ”。这是Michael Sahoto / Agilitrix根据Schneider的书撰写的文化图表:

据我所知,国防部的官方政策通常不禁止使用动态语言。
由国防部开发或采购的软件标准由国防信息系统局(DISA)颁布。他们的应用程序安全性-应用程序安全性和开发安全性技术实施指南(STIG)没有禁止任何特定语言。它没有提到Ruby,但是提到了类似动态的Perl和Python。它在各种主题的上下文中提及了它们(遵循既定的编码标准,避免了命令注入漏洞等)。
您可能看到的是一个过于严格的扫描工具(STIG中提到了几种不同的工具,每个工具可能都有自己对规则的解释)和/或对其输出的过于严格的解释。