Java程序安全
(class: Test1, method: main signature: ([Ljava/lang/String;)V)
Incompatible object argument for function call
如果你关掉校验器或是你找到一处虚拟机漏洞并非常规地通过了校验器的检查,那非法代码就要启动了。执行下面的命令,我接收到值:1234—整型变量值。
java -noverify Test1
这个列子并无多大害处,但潜在的危害确是巨大的。以上这样的技术如果同虚拟机漏洞联系起来,造成未被检查的代码得以执行,那么这将造成严重的类型混乱。
·类型混乱
类型的概念对java编程语言来说是浑然一体的。每个值都同一种类型相关联,JVM就是用值的类型来决定什么样的操作可以作用在什么样的值上。
程序的类型信息对于虚拟机安全是至关重要的。一个被恶意的,未经验证的代码启动的类型混淆攻击会试图让JVM相信伪装成为一个类实列的内存块确实是是另一个类的实列,以此进行攻击。如果攻击成功,程序就会以设计者意想不到的方式来操作类实列。这种攻击称为“类型混淆攻击”,因为虚拟机已经闹不清被修改的类的类型。
如果类经过了完全的验证,那么“类型混淆攻击”是不会发生的。在上面的第二个列表中,校验器捕获了这个企图并抛出了异常。也就是说,只要校验器没有被关闭或是被绕过,那么安全就是能够保障的。
幸运的是,我所担心的Java字节码校验器最后的一个漏洞在1999年末被发现。基于这个事实,你可能会认为自己不会在陷入危险中,然而,这过于疏忽大意了。
虽然漏洞越来越少,但还是有充足的机会留给狡猾的代码混入程序之中。记住,你可以手工关闭校验器检验。在接下来的文章中中,我列举出三种主要的java程序,以向大家示列在怎样的环境下关掉校验器。其中一个程序有一个重要的RMI(远程方法调用)组件(如你以后将要学到的,RMI可以让类通过网络载入到程序中,并让你的程序失控)。如果你能避免这种情况发生,就不要关掉校验器验证。
JVM安全是java安全体系中非常重要的一方面。这些未验证代码和类型混淆方面的讨论将有助于你理解为什么。对于下载代码和类型系统来说,没有适当的校验保证,安全计算将成为一句空话。
?
?
?
偷听以及意外或是恶意的修改等方面。
我广泛涉猎了用于加强安全通讯的工具以及相应技术(参考http://www.javaworld.com/javaworld/jw-08-2001/jw-0810-howto.html#resources)。这里我更实际的讨论在我们设计以及完成一个网络安全解决方案时所要考虑的事情。
理解你自己要保护什么:
设计一个安全解决方案你首先要从理解需求开始。通过互联网进行金融交易显然比你下载上周体育积分的WEB页面更需要安全。在选择一种技术和开始设计时,你应该考虑一下几个方面:
? 安全设计会增加产品设计及实现的复杂性,以及安装,配置的复杂性,还有对于终端用户也是这样。尽管安全是值得的,但是复杂性则并不是用户所需要的。你打算怎样复杂化你的安全设计呢?
? 安全处理,尤其是加密以及解密,常常都是CPU操作密集型的。多数桌面及服务器系统都有足够强的马力,但是那些缺乏资源的设备,比如蜂窝移动电话,PDAs等常常缺少这种能力。你的目标平台能适于处理这样的负荷吗?
? 同样,安全设计会增加程序代码量。尽管在桌面以及服务器计算机上这个不算太严重的问题,但在嵌入式系统中,这就将会涉及到一些利害关系,特别是那些为JAVA2平台,比如Micro Edition (J2ME)而构建的应用,这样的情况下你又能处理好负荷吗?
比如这里的一个列子,移动信息设备框架(MIDP)第一版,就缺少SSL(安全套接口层)支持――端到端WEB解决方案中最核心的组件――其主要原因就是对于移动设备来说,SSL太过于苯重了。针对这个问题,SUN微系统实验室的VipulGupta为J2ME构建了兼容SSL标准的一个实现。他的这一成果表明了小设备也可以达到让人可以接受的SSL性能。Gupta的这一实现之所以能达到这一目标,是因为它只是支持最流行的密码套件,其余的则经过了削减以适应小设备的要求,当然,这种实现缺少服务器要求的客户端验证(一种很消耗的客户端组件),并且它通过多个到服务器的连接重复使用了RSA(Rivest-Shamir-Adleman)计算。你可以看看网址:http://www.javaworld.com/javaworld/jw-08-2001/jw-0810-howto.html#resources,可以找到更多的信息。
使用合适的技术:
选择一种合适的技术对于实现一种网络安全解决方案来说似乎已经不用多说了。这样的选择将会影响到安全的寿命和质量。JDK提供了大量的安全API函数。下面这张表将有助你为你的方案选择合适的技术。
? 验证和数字签名:JAVA密码系统(java.security)
? 加密/解密和消息验证代码:JAVA密码系统扩展(javax.crypto)
? X.509验证:JAVA密码系统(java.security.cert)
? 可插入的验证和授权:JAVA验证和授权服务(javax.security.auth)
JSK1.4测试版包括:
? Kerberos:GSS(通用安全服务)API(org.ietf.jgss)
? 证书路径确认:证书路径确认API(java.security.cert)
这些标准API处理了大量安全相关的WEB程序以及企业整合任务的问题。
理解网络:
不考虑网络来进行网络安全方案设计显然是不明智的。程序所运行的系统以及基于其上的网络都将在方案设计中给予充分的考虑。
设想一下这个情景:你建立了一个运行在安全网络之上的程序。如果网络确实是安全的――这意味着网络在物理上给保护起来,用户是可信赖的,并经过了仔细的授权――那么在这种情况下你就可以尽量少的关心你程序本身的安全问题。但是,在多数情况下,网络并非如所想像的那样安全,而且开发人员在开发安全系统中往往失败,因为不含安全机制的系统要比有安全机制的系统创建起来要难得多。然而,一些情况证实了这个方法。比如,在一个群集系统中运行了多个程序,并相互通讯,进行负载平衡,这样的情形就有足够的理由要求这个集群成为一个安全的整体,而不是程序本身。
更实际的讲,保护你的程序典型情况下意味着评估运行程序的机器的安全,机器安装环境的安全以及网络,包括接入点。
对接入点进行验证非常重要。对来自针对程序的恶意攻击,我们还可以设下“陷阱”,就是提供这样的一个入口,这个接入点为蛰伏的sniffer,嗅探器活动提供了一个窗口(sniffer是一种代码片断,用于侦听网络通信信息)。通过sniffer收集来的信息可以提供程序的入口。
理解合法使用者和滥用者:
你要记住,所谓的安全解决方案始终是围绕人来建立的,因此你必须理解程序使用者以及不怀好意者的能力和技术。那些“滥用者”,通常比正常用户更精于技术,他们让事情变得更复杂。
在你考虑设计你的程序安全方案时,你必须要考虑那些使用者的技能水平。比如,如果你的用户坚持要把密码记在碎纸上并在监视器上敲打进去,那么你就不必开发出强大的基于密码的安全系统。正如多数人所说,通常境况下,最好的安全是花费预算来进行培训。
对于滥用着来说,事情又有所不同。这些人常常更具有技术天赋,并更易于受到激励,这就要求更强的技术防护,即时的升级补丁包以及警醒的告诫。
全面掌握JAVA安全:
没有强大的网络安全,你的程序以及数据将是不稳定的。我讲过的其它的两部分――虚拟机安全,应用程序安全――和网络安全一起为JAVA程序提供了一个全面的安全图景。为了构建安全的JAVA程序,你必须全面理解以上的三个方面。