Java 的“最终”是否是?关键字真的能提高安全性吗?
虽然在 Java 中使用“final”关键字有很多原因,我不断听到的一个说法是,它使您的代码更加安全。虽然这在这个微不足道的情况下似乎是有意义的:
public class Password
{
public final String passwordHash;
...
}
使用final关键字,您会期望没有恶意代码能够更改变量passwordHash。但是,使用反射可以更改passwordHash字段的最终修饰符。
那么“最终”是否提供了真正的安全性,或者只是安慰剂?
编辑: 有一些非常有趣的讨论,我希望我能接受多个答案。感谢大家的意见。
While there are many reasons to use the 'final' keyword in Java, one of the ones I keep hearing over and over again is that it makes your code more secure. While this seems to make sense in this trivial case:
public class Password
{
public final String passwordHash;
...
}
With the final keyword, you would expect that no malicious code would be able to change the variable passwordHash. However, using reflection it is possible to change the final modifier on the passwordHash field.
So does 'final' provide any real security, or is it just placebo?
Edit:
There is some really interesting discussion, and I wish I could accept more than one answer. Thanks everyone for your input.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
我非常确定 Final 是一种设计构造,就像类声明中的访问修饰符一样 - 它是一种表达和强制设计的方式。
I am pretty sure final is a design construct in much the same way access modifiers are in a class declarations - it's a way to express and enforce design.
它更多的是“改变”东西而不是“保护”。最终关键字只是放弃了更改/修改/扩展任何方法的能力。
It is more about "changing" the stuff rather than "securing". The final keywords simply puts away the ability to change/modify/extend any method.
Final 还提高了性能/内存管理。
Final also improves performance/memory management.
“final”关键字确实有一些安全隐患。想象一下,您正在设计一个安全系统,其中有一个服务,给定一个字符串,当且仅当该字符串有效时才执行某些操作。你可能会写:
如果 String 不是最终的,一些聪明的攻击者可以子类化 String。它们的字符串不像普通 String 类那样是不可变的 - 事实上,它们可以生成另一个线程,并尝试通过在 checkValidity 之后但在您实际使用参数之前更改参数来攻击您的方法。然后你的“有用的任务”突然做了一些完全错误的事情,可能会危及安全。他们刚刚绕过了你的支票!然而,因为 java.lang.String 是最终的,所以当您请求 String 参数时,您可以很好地保证它实际上是标准的不可变字符串。这是一个相当大的问题 - 有一整类基于系统调用的不正确参数处理的内核模式攻击。
所以是的,final 可以有一些安全考虑。
The "final" keyword does indeed have some security implications. Imagine you are designing a secure system which has a service that, given a string, does something if and only if the string is valid. You might write:
If String were not final, some clever attacker could subclass String. Their string is not immutable like the stock String class is - and in fact, they can spawn another thread and try to do attacks on your method by changing the argument after checkValidity but before you actually use the argument. Then your "useful task" suddenly does something completely wrong, possibly compromising security. They've just bypassed your checks! Because java.lang.String is final, however, you have good guarantees that when you ask for a String parameter it is, in fact, the standard immutable String. This is a pretty big deal - there was an entire class of kernel-mode attacks based around improper parameter handling with syscalls.
So yes, final can have some security considerations.
Final 关键字通常用于保持不变性。对类或方法使用final是为了防止方法之间的联系被破坏。例如,假设类 X 的某个方法的实现假定方法 M 将以某种方式运行。将 X 或 M 声明为 Final 将防止派生类重新定义 M 从而导致 X 行为不正确。它保护对象和方法免遭操纵。但就密码学目的而言,使用 Final 关键字并不是解决方案
Final keyword is usually used to preserve immutability. To use final for classes or methods is to prevent linkages between methods from being broken. For example, suppose the implementation of some method of class X assumes that method M will behave in a certain way. Declaring X or M as final will prevent derived classes from redefining M in such a way as to cause X to behave incorrectly. It secures objects and methods from getting manipulated. But as for cryptography purpose, using final keyword is not the solution
这不是“抵御攻击”意义上的“安全”;而是“安全”。这更像是“更难因错误而搞砸”。
我更喜欢“安全”这个词,因为我觉得它更像是防止事故发生,而不是恶意。
It's not 'security' in the sense of 'withstanding an attack'; it's more like 'harder to mess up by mistake'.
I prefer the word 'safety' as I feel it's more like preventing an accident, not malice.
Java 的
final
关键字不用于这种安全性。它不能替代通常需要的加密解决方案。在这类讨论中,“安全”通常指的是安全对象模型的概念,也就是说,消费者不能出于类的原始作者的非预期目的而操纵对象模型。
Java's
final
keyword is not used for this kind of security. It is not a substitute for what would normally require a cryptographic solution.What is usually meant by "security" in these kinds of discussions is the concept of a secure object model - that is to say an object model that cannot be manipulated by consumers for purposes unintended by the original author of the class.
我不确定我是否会依赖语言结构来增强系统的安全性。
我不认为进行现场决赛会增加针对恶意攻击的安全性(更有可能针对错误,当然还有线程问题)。安全性的唯一“真实形式”是,如果您有一个最终常量字段,它可能会在编译时内联,因此在运行时更改其值不会产生任何影响。
我在继承的背景下更多地听说过最终和安全性。通过将类设为最终类,您可以防止某人对其进行子类化并触摸或覆盖其受保护的成员,但我再次使用它来避免错误而不是防止威胁。
I'm not sure I would rely on language constructs for added security in my system.
I don't think that making a field final would add security against malicious attacks (more likely against mistakes and of course threading issues). The only "real form" of security is that if you have a final constant field it might get inlined at compilation so changing its value at runtime would have no impact.
I've heard of final and security more in the context of inheritance. By making a class final you can prevent someone from subclassing it and touching or overriding its protected members, but again I would use that more to avoid mistake than to prevent threats.
防范什么?
就移动代码(可以在系统之间移动的代码 - applet、midlet、WebStart、RMI/JINI 等)而言,它非常重要。应用于类,并在较小程度上应用于可访问的方法,它可以防止恶意实现。与可访问字段类似,值得注意的静态数据。如果您要编写可能成为库一部分的代码,您需要敏锐地意识到这一点。
对于典型的网络或桌面应用程序代码来说,它的重要性要低得多。然而,字段中缺少它会使代码更难以阅读,并且表明程序员很困惑。这样的代码不太可能仅仅因为写得不好就安全。
Secure against what?
In terms of mobile code (code that can move between systems - applets, midlets, WebStart, RMI/JINI, etc), it is very important. Applied to classes, and to a lesser extent accessible methods, it prevents malicious implementations. Similarly with accessible fields, notable statics. If you are going to write code that may become part of a library, you need to be keenly aware of this.
For typical, say, web or desktop app code, it is far less important. However, its absence on fields makes code more difficult to read and indicates a confused programmer. Such code is unlikely to be secure just because it is badly written.
一般来说,final、private 和其他此类构造应该更多地被视为一般的偏好声明,而不是严格执行的安全性。
但是,如果您控制正在运行的进程的 JVM(假设您在 JVM 上运行其他人提供的代码),那么 Final 和 private 确实可以提供安全性 - 与 Java 的 SecurityManager 相结合。通过反射可以绕过这些限制的事情是可以避免的。
您不能将代码发送到其他人的 JVM 上运行,并认为您通过这种方式隐藏了任何内容。
编辑:汤姆提醒我,通过正确使用最终字段也可以部分防止序列化攻击(即故意提供序列化数据的错误二进制流)。 《Effective Java》还有更多这样的例子。
In general final, private and other such constructs should be considered more as general statements of preference, rather than strictly enforced security.
However, if you control the JVM the process is running on (say you run code provided by others on your JVM) then final and private do indeed provide security - coupled with Java's SecurityManager. The things you can do via reflection to get around these restrictions can be prevented.
What you can't do is ship code to run on someone else's JVM and think that you hide anything this way.
Edit: Tom reminds me that Serialization attacks (that is deliberately providing bad binary streams of serialized data) can also be prevented in part by proper use of final fields. Effective Java has more such examples.
它不会使您的代码更安全,它比其他任何东西都更能保证线程安全。如果变量被标记为final,则在创建对象时必须为其赋值。创建对象后,不能使该变量引用另一个值。
此行为允许您推断对象的状态,并在多个线程同时访问该对象时做出某些假设。
It doesn't make your code more secure, it is more for thread safety than anything else. If a variable is marked final, a value must be assigned to it when the object is created. After object creation, that variable cannot be made to refer to another value.
This behavior allows you to reason about the state of an object and make certain assumptions when multiple threads are accessing it concurrently.
我想当有人说
final
让你的代码更安全时,他们的意思是它可以防止未来的开发人员修改不应该修改的值,或者从不应该修改的类继承。设计为可扩展(并在此过程中导致不可预测的结果)。它与身份验证没有任何(直接)关系。I imagine what someone would mean when they said that
final
makes your code more secure is that it prevents future developers from coming along and modifying values that are not meant to be modified, or inheriting from classes which are not designed to be extended (and causing unpredictable results in the process). It doesn't have anything to do (directly) with authentication.