我无法理解为什么 java 安全编码很重要。例如,为什么将变量声明为私有很重要?我的意思是我知道这将使从类外部访问这些变量变得不可能,但我可以简单地反编译类来获取值。类似地,将一个类定义为 final 将使该类无法子类化。什么时候子类化一个类会对安全造成危险?如果有必要,我可以再次反编译原始类并使用我想要的任何恶意代码重新实现它。当应用程序被用户“信任”时,问题是否会出现?然后人们会以某种方式滥用这种信任吗?基本上我正在寻找的是一个很好的例子,说明为什么应该遵循安全编码准则。
7 回答
编程很难。
如果你定义了严格的 API,不暴露不应该暴露的变量(我们喜欢称之为封装),你可以帮助你的 API 的用户,从而使编程更容易。这被认为是一件好事。
原因主要不是“安全性”,如将秘密事物保密,而是清晰、简单和易于理解。
作为奖励,如果您知道 API 的用户没有在您背后更改“您的”变量,那么使事情正常工作会容易得多,当然。
它是“安全的”,意味着类内部工作对任何使用它的人都是隐藏的。
术语安全不是在“保护服务器”中使用的,用于表示一个类的用户不必担心该类将如何执行他想要的任务。
以你为例:
暴露一个类的变量会让你的类的用户知道他们的存在,这是你不想要的,例如:你只需按下一个按钮来打开灯,你现在不需要在里面是铜还是执行任务所需的其他东西。
Java 是一门面向对象的编程语言,而面向对象编程的关键概念之一就是封装。
封装背后的想法是“隐藏”实现细节,例如保存对象状态的内部变量和算法等内部工作,只提供其他对象可以使用的接口,以便与对象执行功能.
使用这个概念,人们想通过使用private
变量来隐藏内部状态,以防止其他对象直接影响内部状态。在 Java 中,通常会看到 getter 和 setter(例如getColor
和setColor
)来处理对象。
此外,封装也可以增加代码的健壮性。
例如,通过限制对内部状态的访问,可以在更改对象之前执行一些健全性检查。
作为一个可靠的例子,假设有一个Score
对象的percent
值介于0
和之间100
。通过提供一种setPercent(int)
验证指定值是否在允许范围内的方法,可以防止将Score
对象设置为不可接受的状态。
因此,如果方法导致错误或如果指定的值不可接受,则尝试通过编写类似语句来直接操作内部状态score.percent = 150
是可以避免的。setPercent
Exception
这里有两个问题。
第一次将变量声明为受保护或私有时,它们不会成为您的公共 API 的一部分。未来其他类可能取决于您的类,如果您想包含新功能、提高性能等,请尽可能自由地进行更改。如果您的所有价值观都是公开的,而不是您内部的所有价值观价值观和机制是公开的。更改它们可能会破坏其他依赖于您的课程。
第二,当暴露变量时,它允许其他类改变你的值。如果他们改变了你的内部价值观,可能会破坏你的程序,并产生奇怪的意外行为。如果您创建的系统依赖于您的类的准确性能,并且内部值发生了变化,那么您将无法再依赖该系统。子类化使这更加复杂。您的系统可能依赖某个特定类型的类来执行预期的操作。通过子类化,可以创建一个看起来是相同类型但不执行预期操作的新类。
例如,如果您有一个带有受保护函数 getArea() 的类 square,您希望返回正方形的面积。但是,可以创建一个扩展正方形的新类,例如矩形类扩展正方形。现在rectange 可以覆盖getArea(),但它仍然是square 类型,这可能会破坏一些依赖于square 功能的东西。通过使您的课程成为最终课程,您断言这永远不会在您的系统中发生。
这种类型的“安全编码”不会阻止别人看到你的源代码,但它有助于使你的代码在未来更加可靠和可用。
只是补充一下其他人已经说过的话:其中一些功能也可以简单地视为一种表达意图的方式。如果我创建一个成员private
,我会让其他人“不可能”访问它(这是可能的,但这不是这里的重点),但更重要的是我告诉用户这是一个实现细节,他们不应该依赖它。
想象一下,如果您的对象具有非私有(隐藏)的内部属性,并且您访问此属性的代码恰好在多线程环境中运行,因此 N 个线程将同时开始访问它,5 个线程想更改此属性,4 个到读。您无法确保事情会整齐地运行,两个线程都不知道它当前保存了哪些数据,并且它是否成功地更改了该对象的属性。
您将必须编写一段特殊的代码,该代码将负责处理同步访问,但这仍然不能保证您的代码将正常工作,因为您仍然必须检查程序中访问该属性的其余 680 个类而不是直接访问它.
简而言之,您遇到了一个大问题,调试是一场噩梦,因为您不知道数据何时被更改,哪个线程执行此操作,从何处发生等。
如果您不封装,这只是发生的一种情况......
好东西,你的代码运行速度快了 1%,堆栈上的负载更少,你已经获得了可能微不足道的性能提升,你将付出系统周期性崩溃和成功调试的小机会。
术语“安全编码”是指构建明显试图避免安全漏洞的软件,无论是 C、Java、Ruby、汇编语言还是其他任何语言。在选择安全的语言系统之后,其中最核心的部分可能是保持良好的编程实践。如果一个程序不清楚,那么你几乎没有机会相信它。
对于 Java,有两个值得注意的指南:
- Java 编程语言的安全编码指南,2.0 版。两年前更新,需要更新。
- 用于 Java 的 CERT Sun Microsystems 安全编码标准。CERT 和 Sun 都支持的新 wiki,可以根据您认为重要的内容进行更新。这比 Sun 的指导方针要宽泛得多。例如,Sun 指南并不真正关心整数溢出,因为所有数组边界都经过检查,但 wiki 这样做是因为它仍然会导致程序错误。
在 Java 中有两种不同的安全编码模式。
一方面,您正在处理的代码可能不具备您的代码所具有的所有特权。例如,如果您正在编写库或签名代码,则需要这样做。恶意代码应该不可能以意想不到的方式利用您的权限。这是困难的!
更常见的是,您正在处理仅处理不受信任数据的程序。例如,Web 服务器(想想 XSS 和 SQL 注入)和处理不受信任文件的桌面应用程序(通常问题在于 C 代码具有缓冲区溢出 - 真正的 C++ 更好)。在某些情况下,拒绝服务 (DoS) 可能是一个严重的问题。
有一些重叠。例如,解释器以解释器代码的权限运行,并且可能非常“强大”。