我对为什么要进行Java安全编码感到困惑。例如,为什么声明变量为私有很重要?我的意思是,我明白这会使得从类外部访问这些变量变得不可能,但我可以简单地反编译该类以获取值。 同样,将类定义为final将使得无法对该类进行子类化。何时对一个类进行子类化会对安全造成危险?同样,如果需要,我可以反编译原始类并使用任何恶意代码重新实现它。 问题出在应用程序被用户“信任”时吗?人们能否以某种方式滥用这种信任? 基本上,我正在寻找一些好的例子来说明为什么应遵循安全编码准则。
我对为什么要进行Java安全编码感到困惑。例如,为什么声明变量为私有很重要?我的意思是,我明白这会使得从类外部访问这些变量变得不可能,但我可以简单地反编译该类以获取值。 同样,将类定义为final将使得无法对该类进行子类化。何时对一个类进行子类化会对安全造成危险?同样,如果需要,我可以反编译原始类并使用任何恶意代码重新实现它。 问题出在应用程序被用户“信任”时吗?人们能否以某种方式滥用这种信任? 基本上,我正在寻找一些好的例子来说明为什么应遵循安全编码准则。
编程很难。
如果您定义了严格的API,并且不公开不应公开的变量(我们称之为封装),则可以帮助API的用户,从而使编程更容易。这被认为是一件好事。
原因主要不是“安全”,即保守秘密事项,而是清晰、简单和易于理解。
当然,作为额外的好处,如果您知道API的用户没有在背后更改“您”的变量,则更容易使事情正常工作。
Java是一种面向对象的编程语言,而面向对象编程的关键概念之一是封装。
封装的思想是“隐藏”实现细节,例如保存对象状态的内部变量和算法等内部工作,并仅提供其他对象可以使用的接口来执行对象功能。
使用该概念,人们希望通过使用private
变量来隐藏内部状态,以防止其他对象直接影响内部状态。在Java中,通常会看到getter和setter(例如getColor
和setColor
)来处理对象。
此外,封装还可以增加代码的鲁棒性。
例如,通过限制对内部状态的访问,可以在更改对象之前执行某些合理性检查。
作为一个实例,假设有一个 Score 对象,它应该具有介于 0 和 100 之间的百分比值。通过提供一个 setPercent(int) 方法来验证指定值是否在允许范围内,可以防止 Score 对象被设置为不可接受的状态。因此,如果 setPercent 方法导致错误或抛出异常,则可以防止直接通过编写类似于 score.percent = 150 的语句来操纵内部状态。private
,我就使得其他人“无法”访问它(虽然这是可能的,但这不是重点),更重要的是,我告诉用户这是一个实现细节,他们不应该依赖它。想象一下,如果您的对象具有不是私有(隐藏)的内部属性,并且运行代码访问此属性的多线程环境中,N个线程将同时开始访问它,其中5个线程想要更改此属性,4个线程想要读取。没有办法确保事情会顺利进行,也没有线程知道它在这一刻持有哪些数据以及是否成功更改了该对象的属性。
您将不得不编写特殊的代码片段,负责处理同步访问,但仍然不能保证您的代码将正常工作,因为您仍然必须检查程序中其余680个类是否直接访问该属性。
简而言之,您面临着巨大的问题,调试是一场噩梦,因为您不知道数据何时被更改,哪个线程进行了更改,从哪里发生等等。
这只是不封装时发生的一个场景...
好消息是,您的代码运行速度快了1%,堆栈上的负载较小,您可能获得了可以忽略不计的性能提升,但您将付出系统定期崩溃和成功调试的微小机会的代价。
「安全编码」一词指的是构建软件时明确尝试回避安全漏洞的过程,无论是在 C、Java、Ruby、汇编语言或其他任何语言中。也许最核心的部分,在选择安全的语言系统之后,就是要坚持良好的编程实践。如果程序不清晰,那么它被认为是值得信任的机会就很小了。
Java 有两个著名的指南:
在Java中,有两种不同的安全编码模式。
其中一种是处理可能没有您代码所有权限的代码。例如,如果您正在编写库或签署代码,则需要这样做。恶意代码不应该能够以意外的方式利用您的权限。这很困难!
更常见的情况是处理仅涉及不受信任数据的程序。例如,Web服务器(考虑XSS和SQL注入)和处理不受信任文件的桌面应用程序(通常问题出现在具有缓冲区溢出的C代码上 - 真正的C ++更好)。在某些情况下,拒绝服务(DoS)可能是一个严重问题。
有一些重叠。例如,解释器以解释器代码的权限运行,可能非常“强大”。