Java安全——语言本身的设计

内在安全机制

Java语言本身的安全机制是要保护内存资源——保证内存完整性,核心的安全特性要确保程序不能非法解析或修改驻留在内存中的机密信息。从语言本身的设计角度考虑,就是要设计一组规则,在所构建的运行环境中,程序对象对内存的操作是经过定义的而不是任意的。

Java的强制约束

  1. 必须严格遵循访问方法的要求。必须依照程序员制定的访问级别进行相关方法的操作。如果不遵守则会产生异常。
  2. 不能访问任意的内存地址。 Java没有指针的概念,因此不会像C++一样拿到一个指针强制转换成内存指针,再利用查找内存的方法得到本不该被获取的信息。
  3. 不能对final实体再做改动。
  4. 变量在初始化前不能使用。如果能读取未初始化的变量,就等同于可以读取任意内存地址。可以通过声明一个大的对象而盗取主机内存中的信息。
  5. 对于所有数组访问进行越界检查。越界检查除了可以减少程序错误意外,另一大贡献就是安全保障。如果整数数组后紧接着存放一个字符数组,那么通过整数数组的越界写,可以改变字符数组的内容。
  6. 对象不能任意强制转换为其他类型的对象。这种类型转换的限制不仅在编译器层面,在JVM里也做了强限制,在绕过编译器的转换(比如把被转换的对象标记为Object),JVM在运行时检查也会抛出ClassCastException

Java语言通过上面几条约束,从语言层面保护了内存,不会允许程序在没有获得正确的访问权限时读取到本不该访问的内存。

序列化怎么保障安全

这个题目不太好,因为序列化无法保证安全。Java允许通过实现java.io.Serializable接口来使内存对象序列化为一组字节码。这组字节码通过网络或者文件等方式被其他地方的代码读取并重建一个相同结构和内容的内存对象。这是Java的序列化和反序列化过程。作为一组字节码存储在磁盘文件或者数据流里,原则上是允许被修改的。那说白了,序列化无法保障安全。但是考虑到Java语言要设计支持一组规则,至于序列化的安全,就交给使用者自己保障。

序列化的安全设计规则:

  1. 可序列化的对象必须实现java.io.Serializable接口,这相当于给用户打预防针,告知其要考虑这个对象的安全问题。
  2. 序列化对象声明transient变量,那么该变量不被序列化。这相当于提供了保护数据的机制。

单单从这两个层面看,已经是Java语言能做到的最大化问题了。再多,则影响到了序列化本身要实现的功能。那么具体怎么做呢?就像我们常规传输数据一样——加密,你可以选择对要序列化的变量和属性加密,在反序列化时解密来增强安全。

安全规则实施

当然这里讲到的实施其实不仅仅针对安全,但是这些实施阶段确实增强了安全性。换个角度,我们其实是看Java程序的运行过程如何对应这些语言设计规则。

编译

编译阶段,可以避免“约束”中提到的前4条规则。数组越界是运行时问题,而类型转换,在编译阶段只能做到无关类型的转换,比如下例:

    static class Foo {
        int x;
    }

    static class Bar {
        int x;
    }

    public static void main(String[] args) {
        Foo foo = new Foo();
        Bar bar = (Bar) foo;
    }

这时编译器会提示“Cannot cast from Foo to Bar”。但是如果稍作修改,将Foo替换为Object,则编译器无能为力。

    static class Foo {
        int x;
    }

    static class Bar {
        int x;
    }

    public static void main(String[] args) {
        Object foo = new Foo();
        Bar bar = (Bar) foo;
    }

链接

我们都知道,编译只是做Class文件,JVM的介入是要从load class开始的。而加载完class文件后的第一件事就是链接。链接包括验证、准备和解析这几个步骤,而验证阶段,就是安全规则介入的一个阶段。验证阶段就引入了JVM的字节码校验器。

这个阶段主要是来防御恶意编译器的攻击,或者是一些无意的程序错误。比如一个类FooBar设计如下:

public class FooBar {

    public String val = "abcd";
}

类FooBarTest引用了这个类并更改了val变量:

public class FooBarTest {

    public static void main(String[] args) {
        FooBar foobar = new FooBar();
        foobar.val = "abcde";
        System.out.println(foobar.val);
    }

}

这时我们编译并运行FooBarTest,会打印abcde。而现在如果去修复FooBar,将public改为private,然后只编译FooBar,则不会发生错误。然而本来这时也编译FooBarTest会导致编译错的。但是因为疏忽导致没有这么做,那么如果没有链接校验,FooBarTest就是错误的执行了。然而因为字节码校验器的存在,运行FooBarTest会抛出

Exception in thread "main" java.lang.IllegalAccessError: tried to access field FooBar.val from class FooBarTest
    at FooBarTest.main(FooBarTest.java:5)

优雅的解决了这个问题。

字节码校验器通过两部分来实现这种校验。首先,其作为一个微型的定理证明机,会证明class满足下列条件(只做检查):

  1. 类文件格式正确;
  2. 不会基于final派生子类,也不会覆盖final方法;
  3. 只有一个父类;
  4. 没有对primitive类型数据进行非法转型(int->Object);
  5. 对象之间没有进行类型转换;
  6. 操作数栈不会出现溢出。

接下来,在代码真正执行前进行校验(称为延迟校验)。比如刚才举例中提到的异常,就是校验器在校验字段的访问合法性时抛出的。

运行

上面两个阶段检查不了的规则,放到运行时检查:数组越界和类型转换。运行时抛出ArrayIndexOutOfBoundExceptionClassCastException

结语

Java语言层面的安全设计,本身也可以看出设计思路是弥补原有C和C++的部分短板而设计的。主要目标还是防止非法内存访问。但是加入了这些限制也带来了性能的缺失,这本身就是一个trade off。

时间: 2024-10-28 04:32:10

Java安全——语言本身的设计的相关文章

选择合适的java脚本语言

脚本 选择合适的java脚本语言--如果你正考虑在java应用中集成脚本解释器,最难得是决定使用那种 摘要:脚本语言已经向java开发者证明了它的价值.它让客户实现应用功能的扩展和界面的个性化,从而程序的价值得以提升.另外,它们可以显著的简化程序开发者的设计任务,通过实现动态定义.装载和评估.对于开发人员,集成一种或多种脚本语言的任务是简单的,从越来越长的可选列表中选出一个确实困难的.本文描述了一些伴随java应用中脚本语言支持的问题,并从不同角度比较了Groovy, JudoScript, P

从javascript语言本身谈项目实战_javascript技巧

从javascript语言本身谈项目实战                                              dulao5  2005-1-15        随着ajax的升温,javascript越来越得到人们的重视.重要的是,ajax在一定程度上带来了web软件架构上的变化,人们把越来越多的功能分配到客户端实现,javascript子项目规模越来越大.如何更高效的使用javascript,如何更科学的组织javascript,如何更顺利的保证项目进展?我想就我的经验谈

ejb-请问基于Java EE的构件规范设计开发构件,指的是使用EJB框架开发构件吗?

问题描述 请问基于Java EE的构件规范设计开发构件,指的是使用EJB框架开发构件吗? 我现在要完成的任务是开发一个可重用构件,这个构件要实现的功能是系统中一个数据处理模块.要求在Java EE 支撑平台下开发.我现在不太能理解这个构件的开发过程.查了资料得知javabean和ejb都可以用Java语言开发组件.javabean比较简单是一般和JSP配合的,开发比较小型的组件使用的.EJB更为复杂功能也全面,但是我的这个系统不是分布式的,也不需要与服务器进行交互.用EJB开发是不是有些不机智?

介绍Java下一代语言Clojure、Scala和Groovy的共同点

在 上一期文章 中,我介绍了 Java 下一代语言用来消除 Java 语言中华而不实的东西和复杂性的创新方式.在这一期文章中,我将展示这些语言如何消除 Java 的一些瑕疵:异常.语句与表达式,以及围绕 http://www.aliyun.com/zixun/aggregation/19527.html">null 的边缘情况. 表达式 Java 语言从 C 语言那里继承的一项传承是区分编程语言 和编程表达式.Java 语句的示例包括使用 if 或 while 的代码行,以及使用 void

认识不同Java.net语言中类似的函数结构

函数式编程语言包含多个系列的常见函数.但http://www.aliyun.com/zixun/aggregation/7155.html">开发人员有时很难在语言之间进行切换,因为熟悉的函数具有不熟悉的名称.函数式语言倾向于基于函数范例来命名这些常见函数.从脚本背景衍生而来的语言倾向于使用更具描述性的名称(有时是多个名称,包含多个指向同一个函数的别名). 在本期文章中,我将继续探讨 3 种重要函数(过滤.映射和缩减)的实用性,展示来自每种 Java 下一代语言的实现细节.文中的讨论和示例

数据结构 c语言-C语言数据结构课程设计实现一个集合数据结构

问题描述 C语言数据结构课程设计实现一个集合数据结构 题目:设计并实现一个集合数据结构Set.一个集合中没有重复元素,支持下列运算: boolean add(E o) 如果 set 中尚未存在指定的元素o,则添加此元素. boolean addAll(Set c) 如果 set 中没有指定集合c中的所有元素,则将其添加到此 set 中. void clear() 移除 set 中的所有元素. boolean contains(E o) 如果 set 包含指定的元素o,则返回 true. bool

源代码-基于JAVA的电子商城的设计

问题描述 基于JAVA的电子商城的设计 求基于Java的电子商城设计的源代码,最好是可以直接跑起来的,代码不要太复杂,简单易懂,求大神资源! 解决方案 关于商城系统中商品类别的设计 解决方案二: 看看这个 java开发SHOP电子商城网站平台shop++http://www.zuidaima.com/share/2043180788730880.htm 解决方案三: google里面输入完整下面一行 site:download.csdn.net java 商城 就有一波源代码赶来. 解决方案四:

java试题库管理系统的设计

问题描述 java试题库管理系统的设计 题库的管理(题型,内容,难易程度,知识点)和试题的生成 试题的统计与查询 解决方案 java swing开发毕业设计-进销存管理系统源代码下载 解决方案二: 我这里有http://blog.sina.com.cn/s/blog_6548a1010100h0e2.html 解决方案三: 我Q是:103648905

Java跨语言调用实现方案

Java 跨语言实现方案 背景: 在大型分布式 java 应用中,为了方便开发者,通常底层的 rpc 框架都会做一些调用的封装,让应用层开发人员在开发服务的时候只用编写简单的 pojo 对象就可以了,如流行的 spring remoting , jboss remoting 等等,都有这样的效果. 随着业务的需要,可能上层应用希望采用非 java 技术,如 php , ruby on rails ,而由于 java gc 和内存模型的限制,可能有的底层服务又需要采用更高性能和更加灵活的技术,如果