私有方法真的安全吗?

Posted

技术标签:

【中文标题】私有方法真的安全吗?【英文标题】:Are private methods really safe? 【发布时间】:2013-11-20 07:40:21 【问题描述】:

在 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 Documentation 的一些观点来澄清我的问题。

选择访问级别的提示:

如果其他程序员使用你的类,你要确保错误 不会发生误用。访问级别可以帮助您做到这一点。使用 对特定的有意义的最严格的访问级别 成员。除非您有充分的理由不这样做,否则请使用私有。

【问题讨论】:

使用混淆器可能会有所帮助,因为getDeclaredMethods 会返回看起来像垃圾的名称。 私人、受保护的公共等不是为了安全,而是为了避免善意的人犯错。不要将其用作安全措施 Java 代码无论如何都是可反编译的。 “攻击者”可以下载 Java 反编译器并读取您的代码,或者将“私有”更改为“公共”。 详细说明@RichardTingle 的评论(+1 顺便说一句)。安全性和安全性之间存在巨大而重要的区别。后者是使用访问修饰符缓解的问题;不要意外弄坏东西 对于不存在访问修饰符的程序员来说,这一切都很清楚,比如在 Python 中。在这些语言中,私有/公共只是通过名称中的约定来区分(在 python 中,任何以单个下划线开头的东西都应该被认为是私有的)。这清楚地表明,将某些内容标记为“私有”确实不会增加任何安全性,但这只是说明人们应该使用您的 API 的一种简单方式。我怀疑让编译器检查这些东西是否有帮助,因为在没有“外部”帮助的情况下很容易遵循约定。 【参考方案1】:

这取决于您所说的“安全”是什么意思。如果您使用允许此类事情的安全管理器运行,那么是的,您可以通过反射做各种令人讨厌的事情。但是在那种环境下,库可能只是被修改以使方法公开。

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

【讨论】:

切线,我知道,但你能否详细说明一下在这个意义上更严格的经理会是什么? @Gray:SecurityManager 的一个实例,它基本上会在相关的check* 调用上引发异常。【参考方案2】:

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

除了了解数据和代码方法之外,还有责任知道何时以及如何使用它。你不会在你的 inIt 方法上设置 private 以防止有人发现它,你这样做是因为(a)他们不会知道你只在 foo 之后调用它并且只有当 bar = 3.1415 和(b)因为知道这对他们没有好处。

访问修饰符可以用一个简单的短语“TMI,伙计,我所以不需要知道”来概括。

【讨论】:

很好的答案,但我确实需要谷歌才能发现 TMI 意味着太多信息。我想我需要在山谷里花更多的时间:-)【参考方案3】:

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

【讨论】:

【参考方案4】:

问题是你想从谁那里保存它。在我看来,你的代码的这样一个客户端是一个不知所措的人。

任何试图访问上述类的private 成员的代码(由您或其他人编写)实际上都是在自掘坟墓。 private 成员不参与 public API,如有更改,恕不另行通知。如果客户端碰巧以上述方式使用了其中一个这样的私有成员,那么如果它升级到修改了私有成员的 API 的更新版本,它就会中断。

【讨论】:

【参考方案5】:

有了设施,就有责任。有些事情你不能做,有些事情你可以做但你不应该做。

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

【讨论】:

【参考方案6】:

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

您的公开可用函数应该为您的代码提供一个清晰、有据可查、很少更改的接口。您的私有函数可以被视为一个实现细节,并且可能会随着时间而改变,因此直接使用并不安全。

如果客户端程序员竭尽全力规避这些抽象,他们在某种程度上表明他们知道自己在做什么。更重要的是,他们知道它不受支持,并且可能会停止使用您的代码的未来版本。

【讨论】:

【参考方案7】:

private 不是为了安全,而是为了保持代码的整洁和防止错误。它允许用户模块化代码(以及如何开发),而不必担心所有其他模块的细节

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

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

【讨论】:

以上是关于私有方法真的安全吗?的主要内容,如果未能解决你的问题,请参考以下文章

我可以使用 aws amplify 和 @auth 装饰器将 GraphQL 突变设为私有吗?这被认为是一种安全的方法吗?

在 onEnter 路由上使用 auth 函数与使用高阶函数,这两种方法真的安全吗?

HTTPS 为啥安全? 真的安全吗?

软件快速交付真的需要以安全为代价吗?

掌上折扣app是真的吗安全吗

哈希机制真的安全吗?