由于私有变量不能受到限制,Reflection是否有缺点?


14

private改性剂是用来限制在类的外部访问,但使用反射其他类可以访问私有方法和字段。因此,我想知道如果它是需求的一部分,我们如何才能限制可访问性。


2
低信任度代码不能使用私有反射(至少不能在其他程序集上使用,我忘记了细节)。完全信任代码可以简单地使用指针来绕过流程中的任何限制。
CodesInChaos

55
私有访问修饰符主要用于告诉程序员“不要从类外部使用它,如果确实要使用,请不要抱怨下一个版本是否破坏了您的代码”,而不是严格执行的安全功能。
CodesInChaos


4
用户还可以修补您的代码以执行所需的任何操作。除了DRM的部分例外(其功能不足以提供持久的保护),任何有权访问您的应用程序(二进制文件或源代码)的人都可以使用它进行任何操作。
布莱恩(Brian)

6
这不是特定语言的问题吗?反射在不同语言中的运作方式有所不同。我想知道这个问题是否应该带有Java或其他标签。
韦恩·康拉德

Answers:


54

访问修饰符的目的是通知开发人员有关类的公共接口是什么的代码。它们绝不是安全措施,并且从字面上看也不会隐藏或保护任何信息。


33
这并非普遍如此。引用Eric Lippert的话:“ CLR中的访问修饰符是安全性功能。访问规则已与安全性和类型安全性系统彻底融合。”在C#中,反射仅可用于在完全信任下运行的代码。这不适用于(并且不能)应用于运行代码的系统的恶意用户。但是,它确实适用于恶意插件。
布莱恩(Brian)

5
@Brian Brian提到的相关问题是系统在不完全信任第三方代码的情况下允许其运行。示例包括浏览器沙箱(例如,令人讨厌的小程序),谷歌应用引擎Azure。对于Azure来说,允许不受信任的代码浏览平台核心库的细节真是愚蠢的。
JimmyJames

3
@Brian这不是100%正确的-您可以在部分受信任的代码中执行一些反射操作;它只是不允许您执行访问私有字段之类的操作。
六安2013年

1
@Brian,直到有人发现允许他们绕过限制的漏洞或社会工程。尝试以这种方式使用它们是没有意义的。那不是他们的主要目的。
jpmc26 2013年

31

引用Herb Sutter的类访问权限

“这里的问题是防止墨菲与防止马基雅维利……也就是说,防止意外误用(该语言很好用)与防止故意滥用(实际上是不可能的)。最后,如果程序员非常想破坏系统,他会找到办法”


2
这里你需要的沙箱不受信任的代码倍,但是这是一个艰巨的任务。防止错误(墨菲)是更常见的情况。
Paul Draper

#define private public(忽略它实际上是未定义行为),瞧,我可以从外部完全访问类的受限部分。
bolov's

保护儿童不受虐待故意可能在理论上是不可能的,但它是有效可行的,通过使滥用足够困难,这很少发生。重要的是要弄清楚这一点。否则,在诸如生命攸关的医疗设备之类的情况下,根本无法使用软件。
MarkJ

@MarkJ。赫伯·萨特(Herb Sutter)的言论是关于首先编写该类的开发人员和他的队友故意滥用的。我认为无法通过语言功能来防止这种滥用。
Nemanja Trifunovic

@bolov我认为特技与语言有关。尽管C / C ++预处理器可能会让您摆脱困境,但没有它们的任何东西都可能会给出“无法在#define中使用保留字”错误。
Dan在Firelight的抚养下(

10

不,这实际上是一个重要的优势。仅仅因为某些开发人员不认为任何人都需要访问某些内部状态并不意味着就不会出现合法的用例。在这些情况下,使用反射对对象进行手术可能是最后的选择。我不得不多次使用这种技术。


1
换句话说,这是一种规避可能损坏的API的方法-无论是由于需求不完整还是实施不完整。
恢复莫妮卡

4

通过上一层:执行环境,您甚至进一步限制了可访问性。

并非所有语言都有此概念,但至少可以使用Java使用安全管理器,该安全管理器禁止访问私有字段。您可以在运行时手动安装安全管理器,或在jar文件中添加安全策略,然后将其密封以防止修改。

有关在Java中执行此操作的更多信息:反射安全性


3

你在说什么反思?

在许多反射系统中,规避封装是您的代码需要获得的显式功能,并且默认情况下没有此功能。

如果您担心封装,则简单的解决方案是不使用不保留封装的反射系统。


3

在Python中,没有访问修饰符。约定是在下划线前面加上不应从类外部访问的方法和变量。从技术上讲,它是否阻止您从第三方类访问此类字段?一点也不; 但是,如果您这样做了,那您就自己一个人了,并且冒着破坏某件事的风险,而不能责怪其他人。

在C#中,存在访问修饰符,但它们仅是一种约定-由编译器强制执行的约定,但仍是约定。这意味着从技术上讲,仍然可以通过反射或直接篡改内存来访问和更改私有变量(就像游戏培训师一样)。结果是完全一样的:如果通过另一个类的Reflection更改了类的变量,或者通过另一个应用程序的内存篡改更改了类的变量,但它破坏了类中的某些内容,那不是您的错。

请注意,这显然会带来安全问题,第三方可以访问您的数据。这会导致字符串和类似数据结构的加密变体。但是,保护您的代码免于这种使用是与操作系统和代码级访问限制相关的更多内容,并且与反射本身无关。


2
请注意,在C#中,只有完全受信任的代码才能反映私有成员。直接写入进程内存仍然可以工作,但是比本地代码
六安2013年
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.