反射是否打破了私有方法的想法,因为私有方法可以在类之外访问?

时间:2010-07-21 15:00:53

标签: c# java php reflection junit

反射是否打破了私有方法的想法?因为可以从类外部访问私有方法吗? (也许我不明白反思的意思或错过别的东西,请告诉我) http://en.wikipedia.org/wiki/Reflection_%28computer_science%29

修改 如果relection打破了私有方法的想法 - 我们是否只将私有方法用于程序逻辑而不用于程序安全性?

由于

14 个答案:

答案 0 :(得分:26)

  

我们是否仅将私有方法用于程序逻辑而不用于程序安全性?

目前尚不清楚“程序安全”是什么意思。安全无法在真空中讨论;您在考虑哪些资源来防范哪些威胁?

CLR代码访问安全系统旨在保护用户数据的资源免受在用户计算机上运行的恶意部分受信任代码的威胁

因此,CLR中的反射,访问控制和安全性之间的关系很复杂。简单而不完全准确,规则如下:

  • 完全信任意味着完全信任。 完全受信任的代码可以访问流程中的每一位内存。包括私有字段。

  • 在部分信任中反映私有部分的能力由权限控制;如果没有被授予,则部分信任代码可能不会对私有部门进行反思。

有关详细信息,请参阅http://blogs.msdn.com/b/shawnfa/archive/2006/09/29/777047.aspx

  • 桌面CLR支持一种称为“受限跳过可见性”的模式,其中反射和安全系统交互的规则略有不同。基本上, 如果部分受信任的代码从来自相等 less的程序集的类型访问私有字段,则有权使用私有反射的部分受信任的代码可以通过反射访问私有字段信任。

http://blogs.msdn.com/b/shawnfa/archive/2006/10/05/using-lightweight-codegen-from-partial-trust.aspx

了解详情

执行摘要是:您可以将部分受信任的代码锁定到足以使其无法使用反射来查看私有内容。您无法锁定完整信任代码;这就是为什么它被称为“完全信任”。如果你想限制它,那么不信任它

那么:将字段私有化是否保护它免受低信任代码试图读取它的威胁,从而窃取用户的数据? 的。它是否保护它免受高信任代码读取它的威胁? 没有。如果代码既受用户信任又对用户不利,那么用户就会遇到大问题。他们不应该信任该代码。

请注意,例如,将某个字段设为私有不会保护代码中的秘密来自拥有您的代码且对您有敌意的用户。安全系统从恶意代码保护好用户。它不保护来自邪恶用户的好代码 。如果你想私下让某些东西与用户保持一致,那么你就是傻瓜的差事。如果你想把它变成私密的,以保护那些诱骗用户运行恶意低信任代码的邪恶黑客的秘密,那么这是一个很好的技术。

答案 1 :(得分:19)

Reflection提供了一种绕过Java的访问保护修饰符的方法,因此违反了严格的封装,因为它在C ++和Java中实现了。然而,这并不像你想象的那么重要。

访问保护修改器旨在帮助程序员开发模块化的良好分解系统,而不是不妥协的门卫。有时候有很好的理由打破严格的封装,例如 Unit Testing和框架开发

虽然最初可能很难理解访问保护修饰符很容易被绕过,但请记住,有许多语言(PythonRuby等)没有它们所有。这些语言用于构建大型复杂系统,就像提供访问保护的语言一样。

关于访问保护修饰符是帮助还是障碍,存在一些争论。即使您确实重视访问保护,也可以将其视为助手,而不是制作或破坏您的项目。

答案 2 :(得分:13)

是的,但这不是问题。

封装不是关于安全性或秘密,而是关于组织事物。

反射不是“正常”编程的一部分。如果你想用它来打破封装,你接受风险(版本问题等)

只有在没有更好(较少侵入性)的方法来完成某些事情时才应该使用反射。

反思是系统级的“工具”,如持久性映射,应该隐藏在经过良好测试的库中。我会发现在正常的应用程序代码中使用反射是可疑的。

我开始说“这不是问题”。我的意思是:只要您按预期使用反射。小心点。

答案 3 :(得分:8)

就像你的房子。锁只会阻止诚实的人或不愿意选择锁的人。

数据是数据,如果有人确定,他们可以对您的代码做任何事情。字面上的任何东西。

所以,是的,反射将允许人们做你不希望他们对你的代码做的事情,例如访问私有字段和方法。然而,重要的是人们不会意外地这样做。如果他们正在使用反射,他们知道他们正在做他们可能不打算做的事情,就像没有人不小心拿到你前门的锁一样。

答案 4 :(得分:8)

不,反思不会破坏私有方法的想法。至少本身不是。没有任何东西可以说反思不能遵守访问限制。

设计糟糕的反映打破了私有方法的想法,但这与反射本身没有任何关系:任何设计糟糕的都可能打破这个想法私人方法。特别是,私有方法的糟糕设计也可能明显违背私有方法的想法。

设计糟糕的是什么意思?好吧,正如我上面所说,没有什么可以阻止你使用一种语言,其中反射服从访问限制。这个问题是,例如调试器,分析器,覆盖工具,IntelliSense,IDE,一般需要的工具能够违反访问限制。由于没有办法向不同的客户提供不同版本的反射,大多数语言选择安全工具。 (E是反例,它绝对没有任何反射能力,作为有意识的设计选择。)

但是,谁说你不能向不同的客户展示不同版本的反思?嗯,问题很简单,在经典的反射实现中,所有对象都可以反映自己,并且因为每个对象只有一个,所以只能有反射版本。

那么,糟糕设计的概念在哪里?那么,请注意上段中的“负责”一词。每个对象都有责任自我反思。此外,每个对象都要对它首先编写的内容负责。换句话说:每个对象至少具有两个职责。这违反了面向对象设计的基本原则之一:单一责任原则。

解决方案很简单:分解对象。原始对象只负责它最初编写的内容。还有另一个对象(称为镜像因为它是反映其他对象的对象),它负责反射。现在,反思的责任被分解为一个单独的对象,是什么阻止我们拥有一个,而不是两个,三个许多镜像对象?尊重访问限制的访问限制,只允许对象反映自身但不反映任何其他对象,只允许内省(即只读),只允许反映只读的呼叫站点信息(即分析器),提供对整个系统的完全访问权限,包括违反访问限制(对于调试器),只提供对方法名称和签名的只读访问权限,并遵守访问限制(对于IntelliSense)等等... / p>

作为一个很好的奖励,这意味着镜子本质上是反射能力(在能力安全意义上)。 IOW:镜子是十年来协调安全性和运行时动态元编程的圣杯。

镜子的概念最初是在Self中发明的,从那里延伸到Animorphic Smalltalk/Strongtalk然后Newspeak。有趣的是,Java调试接口基于Mirrors,因此Java(或者更确切地说是JVM)的设计者清楚地了解它们,但Java的反思却被打破了。

答案 5 :(得分:5)

正如其他人已经说过的那样。

但是,我记得在Java中可能有一个安全管理器处于活动状态,如果您没有权限,可能会阻止您访问任何私有方法,即使使用反射也是如此。如果您运行本地JVM,则此类管理器通常不活动。

答案 6 :(得分:4)

是的,反思打破了这个想法。本地语言也有一些技巧来破坏OOP规则,例如,在C ++中,可以使用指针技巧更改私有类成员。但是,通过使用这些技巧,我们得到的代码可能与未来的类版本不兼容 - 这是我们为破坏OOP规则而付出的代价。

答案 7 :(得分:4)

是的,Reflection 可以用于违反封装,甚至导致错误的行为。请记住,需要信任程序集来执行反射,因此仍然存在一些保护措施。

答案 8 :(得分:4)

是的,它打破了封装,如果你想要它。但是,它可以很好地使用 - 比如为私有方法编写单元测试,或者有时 - 正如我从自己的经验中学到的 - 绕过第三方API中的错误:)

请注意封装!=安全性。封装是面向对象的设计概念,仅用于改进设计。为了安全起见,java中有SecurityManager

答案 9 :(得分:2)

我认为这是一个意见问题,但如果你使用反射来解决开发人员在课堂上实施的封装,那么你就是在挫败目的。

所以,为了回答你的问题,它打破了封装(或信息隐藏)的想法,它简单地声明私有属性/方法是私有的,因此它们不能在类外部被混淆。

答案 10 :(得分:2)

是。反射打破了封装原则。这不仅是为了访问私有成员,而是暴露一个类的整个结构。

答案 11 :(得分:2)

Reflection使任何CLR类都可以检查和操作其他CLR类的属性和字段,但不一定要明智地这样做。一个类可能会掩盖属性和字段的含义,或者通过让它们以非显而易见的方式依赖于彼此,静态字段,底层OS信息等来保护它们免受篡改。

例如,类可以在某个变量中为其主窗口保留OS句柄的加密版本。使用反射,另一个类可以看到该变量,但不知道加密方法它无法识别它所属的窗口或使变量引用另一个窗口。

我见过自称充当“通用序列化器”的课程;如果应用于像数据存储容器类这样缺少“可序列化”属性但在其他方面完全简单的东西,它们会非常有用。如果应用于任何创作者试图掩盖事物的类别,他们就会产生gobbledygook。

答案 12 :(得分:2)

是的,它确实打破了封装。但在某些情况下使用它有很多充分的理由。

例如:

我在某些网站上使用MSCaptcha,但它会呈现< DIV>围绕< img>标记与我的HTML混淆。然后我可以使用标准< IMG>标记并使用反射来获取验证码的图像ID的值以构建URL。

图片ID是私有属性,但使用反射我可以获得该值。

答案 13 :(得分:1)

通过private / protected / package / public进行访问控制主要不是为了安全。

它可以帮助好人做正确的事,但不会阻止坏人做错事。

一般来说,我们假设其他人都是好人,我们不会将他们的代码包含在我们的应用程序中。

如果你不能相信你所包含的图书馆的那个人,那你就搞砸了。