《Java学习指南》—— 1.5 实现安全

简介: 安全管理器的完整性依赖于Java安全模型在更低层次所提供的保护。如果没有校验器和类加载器所提供的保证,有关系统资源安全性的高级断言就没有意义。由Java字节码校验器所提供的安全表明,解释器不能被破坏或搅扰,而且Java代码必须如期使用组件。

本节书摘来异步社区《Java学习指南》一书中的第1章,第1.5节,作者:【美】Patrick Niemeyer , Daniel Leuck,更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.5 实现安全

创建一种语言从而使自己免于自我伤害,这是一回事;而创建一种语言避免别人攻击你则是另一回事。

封装(encapsulation)是一种将数据和操作隐藏于类中的概念,它是面向对象设计中的重要部分。它将有助于编写简洁的模块化软件。不过,在大多数语言中,数据项的可见性只体现为程序员和编译器之间关系的一部分,这是一个语义问题,而并非数据在运行程序环境中实际安全性的断言。

Bjarne Stroustrup在C++ 中选择了关键字private来指定类的隐藏成员,他可能考虑到了令你免于陷入某个类开发人员所写代码的繁杂细节中,但是却没有考虑到另一个问题,即保护该开发人员的类和对象免于遭受其他人的病毒和特洛伊木马等的攻击。在C或C++ 中可以进行任意的类型强制转换和指针算术运算,这就使得很容易违反类的访问许可,而并不违反该语言的规则。请考虑以下代码:

79f8f398d22f6d2a93baa2476569001def13b773

在这段C++的代码,我们编写了一些违反Finances类封装性的代码,并窃取了一些秘密信息。这种诡计(即滥用无类型指针)在Java中是不能得逞的。如果这个例子还显得有些不切实际,请设想一下,保护运行时环境的基类(系统类)免受类似攻击该是何等重要。如果不可信代码可以破坏对实际资源(如文件系统、网络或窗口系统等)提供访问的组件,那么它自然有机会窃得你的信用卡号。

如果一个Java应用要从Internet上的某个不可信来源动态地下载代码,并且将它与可能包含机密信息的其他应用一同运行,那么就必须尽可能加大保护的力度。Java安全模型在所导入类周围包装了3个保护层,如图1-3所示。

94a0ddfa0dfd6857d0370d7f79dca1bfd0d6a1e4

在外层,应用级安全决策由一个安全管理器做出。安全管理器控制对文件系统、网络端口和窗口环境的这样的系统资源的访问。安全管理器要依赖于类加载器的功能来保护基本的系统类。类加载器负责处理从本地存储或网络加载的。在内层,所有系统安全性最终都要取决于Java校验器,它将确保导入的类的完整性。

Java字节码校验器是Java运行时系统中的一个固定部分。而类加载器和安全管理器(或者更确切地说,应称为安全策略)则是可以有不同实现的组件,即对于加载字节码的不同应用(如applet浏览器和Web浏览器)来说,可以用不同的方式来实现类加载器和安全管理器。以上三者都必须正常工作才能确保Java环境的安全性。

1.5.1 校验器

Java的第一道防线是字节码校验器。校验器在字节码运行前先读取它,并确保其行为正常而且遵循Java语言的基本原则。一个可信的Java编译器是不会生成反常的字节码的。不过,有恶意的人也有可能故意组合出不好的代码,对此加以检测正是校验器的任务。

一旦代码得到校验,就可以认为是安全的,即不存在某些偶然或恶意的错误。例如,得到校验的代码不会仿造引用或违反对象的访问许可(就像前面举的信用卡的例子那样)。它也不会完成非法的类型强制转换或者以非法的方式使用对象。此代码甚至不会导致某些内部错误,如操作数栈上溢出或下溢出。这些就构成了Java安全性的坚实基础。

你可能会有所疑问,许多解释语言不是也隐含地有这种安全性吗?不错,确实如此,例如你无法借助恶意的BASIC代码来破坏解释器,但是要记住,大多数解释语言中的保护都发生在一个更高层次上。这些语言往往有重量级的解释器,它们要完成大量运行时工作,因此无可避免地会较慢,也较为笨重。

比较而言,Java字节码则是相对轻巧的低级指令集。在Java字节码执行前能够对其静态地加以校验,这就使得Java解释器可以全速地运行,并且有充分的安全性,此外还不必进行代价昂贵的运行时检查。这是Java重要的创新之一。

校验器是一种数学“定理证明机”。它从Java字节码入手,应用简单的推导规则来确定字节码在某些方面将是如何表现的。较之于此类其他语言的代码,已编译Java字节码中包含有更多的类型信息,因此这种分析是可能的。字节码还必须遵循一些额外的规则以简化其操作。首先,大多数字节码指令都只是在单个的数据类型上操作。例如,对于栈操作,在Java中有关对象引用的指令和有关各种数字类型的指令都是不同的。类似地,将各种类型的值移入或移出某个局部变量时,也有不同的指令。

其次,对于由任何操作得到的对象,其类型总是提前预知的。不存在使用值的字节码操作,也不存在生成多种类型的值作为输出的字节码操作。因此,总是可以通过查看下一条指令及其操作数来了解将得到的值的类型。

由于操作总是产生一个已知的类型,所以通过查看起始状态,则有可能确定将来某一时刻栈中以及局部变量中所有元素的类型。某一时刻所有类型信息的集合称为栈的类型状态(type state),Java在运行应用之前试图对此加以分析。Java对于此时栈和变量元素的实际值一无所知,只是知道它们是何种元素。不过,这些信息对于加强安全规则以及确保对象不会被非法操作已经足够了。

为了使得对栈的类型状态进行分析变得真正可行,对于Java字节码指令如何执行,Java设置了一个额外限制,即到达代码中同一点的所有路径都必须有相同的类型状态。

1.5.2 类加载器

Java还增加了第2个安全层,即类加载器。类加载器负责将一个或多个Java类的字节码置入到解释器中。每一个要从网络加载类的应用都必须使用类加载器来处理这一任务。

类已得到加载并且通过了校验器检查之后,它将保持与其类加载器的关联。由此,类可以根据其来源而有效地划分到不同的命名空间中。当一个已加载类引用另一个类名时,新类的位置则由原来的类加载器提供。这说明,从一个指定来源获取得到的类,只能与从同一位置得到的其他类进行交互。例如,支持Java的Web浏览器可以使用类加载器为从一个给定URL加载的所有类构建一个单独的空间。基于密码签名的类这样的高级安全性,也可以使用类加载器来实现。

对类的搜索总是从内建Java系统类开始。这些类从Java解释器的类路径(classpath,见第3章)所指定的位置加载。类路径中的类仅由系统加载一次,而且不能被替换。这说明,应用程序不可能使用自己的版本来替换基本系统类以期修改其功能。

1.5.3 安全管理器

最后,安全管理器要负责做出应用级安全决策。安全管理器是一个可以由应用安装的对象,用以限制对系统资源的访问。应用每次试图访问诸如文件系统、网络端口、外部进程以及窗口环境等内容时,都会询问安全管理器;安全管理器可以允许也可以拒绝相应的请求。

对于将不可信代码作为其正常操作一部分来运行的应用来说,安全管理器至关重要。例如,一个支持Java的Web浏览器可以运行applet,而applet可能来自于网络上的不可信的源,这样的浏览器首当其冲就需要安装一个安全管理器。此安全管理器再对此后所允许的访问类型加以限制。这就使得应用在运行任意一段代码前都可以施加一个有效的可信级别。而且一旦安装了安全管理器,它就不能被替换。

安全管理器与一个访问控制器协同工作,通过编辑一个声明性的安全策略文件,从而允许我们从一个较高的层级来实现安全策略。访问策略可能很简单,也可能相当复杂,这取决于特定的应用。有时只需拒绝对所有资源的访问,或者拒绝对于诸如文件系统或网络等通用服务的访问,尽管这种策略很简单,但也已经足够。不过,基于高级信息来制定复杂的决策也是可能的。例如,一个支持Java的Web浏览器可以使用一个访问策略,从而使用户能够指定applet的信任程度,或者允许或拒绝对特定资源的访问,在此可以针对每种不同情况有不同的设置。当然,这里假设浏览器能够确定必须相信哪些applet。稍后将介绍这一问题是如何通过代码标记解决的。

安全管理器的完整性依赖于Java安全模型在更低层次所提供的保护。如果没有校验器和类加载器所提供的保证,有关系统资源安全性的高级断言就没有意义。由Java字节码校验器所提供的安全表明,解释器不能被破坏或搅扰,而且Java代码必须如期使用组件。这反过来说明了类加载器可以保证应用在使用核心Java系统类,而且这些类是访问基本系统资源的唯一途径。适当地施以如上的限制,就可以用一个安全管理器以及用户定义的策略来集中把握对这些资源的控制了。

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

相关文章
|
3月前
|
安全 Java
JAVA 线程安全
【1月更文挑战第4天】JAVA 线程安全
|
4月前
|
监控 安全 数据可视化
【Java】UWB高精度工业人员安全定位系统源码
【Java】UWB高精度工业人员安全定位系统源码
71 0
|
1天前
|
存储 安全 Java
Java中的容器,线程安全和线程不安全
Java中的容器,线程安全和线程不安全
7 1
|
3天前
|
SQL 安全 Java
Java安全编程:防范网络攻击与漏洞
【4月更文挑战第15天】本文强调了Java安全编程的重要性,包括提高系统安全性、降低维护成本和提升用户体验。针对网络攻击和漏洞,提出了防范措施:使用PreparedStatement防SQL注入,过滤和转义用户输入抵御XSS攻击,添加令牌对抗CSRF,限制文件上传类型和大小以防止恶意文件,避免原生序列化并确保数据完整性。及时更新和修复漏洞是关键。程序员应遵循安全编程规范,保障系统安全。
|
20天前
|
存储 安全 Java
【Java技术专题】「攻破技术盲区」攻破Java技术盲点之unsafe类的使用指南(打破Java的安全管控— sun.misc.unsafe)
【Java技术专题】「攻破技术盲区」攻破Java技术盲点之unsafe类的使用指南(打破Java的安全管控— sun.misc.unsafe)
33 0
|
4月前
|
存储 安全 Java
Java并发编程学习4-线程封闭和安全发布
本篇介绍 对象的共享之线程封闭和安全发布
62 2
Java并发编程学习4-线程封闭和安全发布
|
2月前
|
存储 安全 算法
Java泛型与集合:类型安全的集合操作实践
Java泛型与集合:类型安全的集合操作实践
|
3月前
|
算法 搜索推荐 Java
太实用了!阿里内部强推的超全Java算法学习指南,已被彻底征服
算法和数据结构一直以来都是程序员的基本内功。 数据结构可以看作是算法实现的容器,通过一系列特殊结构的数据集合,能够将算法更为高效而可靠地执行起来。
|
4月前
|
监控 安全 数据可视化
java智慧工地源码:助力数字建造、智慧建造、安全建造、绿色建造
智慧工地围绕建设过程管理,建设项目与智能生产、科学管理建设项目信息生态系统集成在一起,该数据在虚拟现实环境中,将物联网收集的工程信息用于数据挖掘和分析,提供过程趋势预测和专家计划,实现工程建设的智能化管理,提高工程管理信息水平,逐步实现绿色建设和生态建设。
21 0
|
4月前
|
传感器 数据采集 安全
Java智慧工地源码:进度、质量、 成本、安全尽在掌握
Java智慧工地源码:进度、质量、 成本、安全尽在掌握
30 0