私有方法真的安全吗?


92

在Java中,private访问修饰符被认为是安全的,因为它在类外部不可见。然后外面的世界也不知道这种方法。

但是我认为Java反射可以用来打破这一规则。考虑以下情况:

public class ProtectedPrivacy{

  private String getInfo(){
     return "confidential"; 
  }

}  

现在从另一堂课我将获得信息:

public class BreakPrivacy{

   public static void main(String[] args) throws Exception {
       ProtectedPrivacy protectedPrivacy = new ProtectedPrivacy();
       Method method = protectedPrivacy.getClass().getDeclaredMethod("getInfo", null);
       method.setAccessible(true);
       Object result = method.invoke(protectedPrivacy);
       System.out.println(result.toString());
   }
} 

这时我只是觉得私有方法仍然安全,因为要做上面的事情我们必须知道方法名称。但是,如果类包含由其他人编写的私有方法,那么我们将看不到那些。

但是,由于下面的代码行,我的观点变得无效。

Method method[] = new ProtectedPrivacy().getClass().getDeclaredMethods();

现在,它method[]包含了需要做的所有事情。我的问题是,有没有一种方法可以避免使用Java反射做这种事情?

我引用Java文档中的一些观点来澄清我的问题。

选择访问级别的提示:

如果其他程序员使用您的类,则要确保不会发生由于滥用而引起的错误。访问级别可以帮助您做到这一点。使用对特定成员有意义的限制性最高的访问级别。除非有充分的理由,否则请使用private。


1
使用混淆器可能会有所帮助,因为getDeclaredMethods会返回看起来像垃圾的名称。
dasblinkenlight

213
私有的,受保护的公众等不是为了安全,而是要避免很好地暗示人们犯错误。请勿将其用作安全措施
理查德·廷格

20
Java代码还是可以反编译的。“攻击者”可以下载Java反编译器并读取您的代码,也可以将“私有”更改为“公开”。
2013年

7
详细阐述@RichardTingle发表的评论(+1 btw)。安全性和安全性之间存在巨大而重要的区别。如果使用访问修饰符可以缓解后者的问题;不会意外
用户

3
对于不存在访问修饰符的程序员(如在Python中),所有这些都很清楚。在这些语言中,名称中的约定仅区分私有/公共(在python中,任何以单个下划线开头的内容都应视为私有)。这使得它很清楚,标志着东西为“私有”并没有增加任何安全性,但它只是说什么的人一个简单的方法应该用你的API。我怀疑是否有编译器检查这些内容是否会有所帮助,因为在没有“外部”帮助的情况下很容易遵循约定。
Bakuriu

Answers:


95

这取决于您所说的“安全”。如果您正在使用允许这种事情的安全管理器运行,那么可以,您可以通过反射来做各种讨厌的事情。但是,在这种环境下,无论如何都可以修改该库以使该方法公开。

在这样的环境中,访问控制实际上是“建议”-您实际上信任代码可以很好地播放。如果您信任正在运行的代码,则应使用限制性更强的安全管理器。


3
切线,我知道,但是您能否详细说明一下在这种意义上限制性更强的经理?
灰色

12
@Gray:SecurityManager的实例check*,基本上会在相关调用上引发异常。
乔恩·斯基特

40

访问修饰符与安全性无关。实际上,您可以并且应该将访问修饰符视为安全性的反面,它不是为了保护您的数据或算法,而是要使人们免于需要了解您的数据和算法的要求。这就是为什么默认修饰符为package的原因-如果他们正在处理Package,则可能已经需要知道它们。

随着对数据和代码方法的了解,还有责任知道何时以及如何使用它。您不会在inIt方法上设置私有项,以免某人对其进行查找,因为这样做(a)他们不会知道您仅在foo之后且bar = 3.1415和(b)时才调用该函数。因为这样做对他们没有好处。

访问改性剂可以在一句简单的话来概括“TMI,伙计,我所以没有必要知道”。


3
很好的答案,但是我确实需要在Google上查明TMI意味着信息太多。我想我需要在山谷里花更多的时间:-)
mikelong 2013年

7

说“安全”,就是在保护您或其他开发人员,他们正在使用您的API通过调用私有方法不损害对象。但是,如果您或他们确实需要调用此方法,则可以使用Reflection来实现。


6

问题是您要从谁那里保存它。我认为,这样的代码客户对这里的客户造成了很大的损失。

任何试图访问private上述类成员的代码(由您或他人编写)本质上都是在挖掘自己的坟墓。private成员未成为公共 API 的一部分,如有更改,恕不另行通知。如果客户端碰巧以上述方式消耗此类私有成员之一,则如果升级到该私有成员被修改的API的较新版本,它将中断。


5

有了设备,责任就来了。有一件事情是,你不能做什么,和你的事情可以做,但你不应该做的。

私有修饰符是作为/以最受限制的方式提供/使用的。在班级外部不可见的成员应定义为私人成员。但是,正如我们所见,这可以通过反射来打破。但这并不意味着您不应该使用私有-否则它们是不安全的。关于您应该明智或建设性地使用事物(例如反射)。


5

假设您信任您的API的客户端程序员,那么另一种看待方式是他们使用这些特定功能的“安全性”。

您的公开可用功能应在代码中提供一个清晰,文档齐全且很少更改的界面。您的私有函数可被视为实现细节,并且可能会随时间而变化,因此直接使用并不安全。

如果客户程序员竭尽所能来规避这些抽象,那么他们就是在声明自己知道自己在做什么。更重要的是,他们了解它不受支持,并且可能会停止使用代码的将来版本。


5

private并不是为了安全,而是为了保持代码干净并防止错误。它使用户可以对代码进行模块化(以及如何开发),而不必担心其他模块的所有细节。

一旦发布代码,人们就可以弄清楚它是如何工作的。如果您最终希望代码在计算机上运行,​​则无法“隐藏”逻辑。甚至编译成二进制文件也是一种混淆的程度。

因此,您无法设置API来执行您不希望其他人调用的特殊操作。对于Web API,您可以将要控制的方法放在服务器端。

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.