`
SunMicro
  • 浏览: 20989 次
社区版块
存档分类
最新评论

JVM and Security primary summary

阅读更多
早期JAVA的安全模型被称作”沙箱(sandbox)“,通过定义这样一个用户可配置的保护域来实现代码的安全性管理,紧接着在JDK1.4中引入了健壮的全功能安全体系,该体系仍然基于沙箱这一概念的,不过新体系的安全策略是向ProtectionDomain授权权限而不是针对单一代码段授权权限

在最初的沙箱定义中,条件过于严格,导致善意的程序运行受限,新的安全平台体系中引入了代码签名和认证的信任模式,在这种模式下,可以根据代码数字签名的可信度给与适当的执行权限,使足够可信度的代码将充分发挥其作用。

沙箱由四个基本部分组成:
  1. 类装载器结构
  2. class文件验证
  3. 内置与jvm的和语言本身的安全特性
  4. 安全管理器和java api
1.类装载器结构

jvm通过类装载器实现类的加载并同时建立不同可信度的命名空间,也叫运行时包,只有被同一类加载器所加载的类相互之间才可见,因为他们在同一命名空间,不同的类加载器会创建不同的命名空间,不同命名空间之间是不允许访问(不可见的。jvm在加载类的过程了使用双亲委托模式,既是发现需要装载某一类的时候,首先将这个任务委托给自己的上级类装载器,依次规律,一般情况下类装载任务最后将委托给启动类装载器,只有在双亲无法完成装载的情况下,才由自己完成装载。双亲委托模式首先降低了恶意代码试图利用系统对java api的信任来达到目的的可能性。设想,一个恶意类被命名为java.lang.String,试图使类加载器误以为该恶意类是java api的一部分,但双亲委托将使用启动类加载器首先寻找java.lang.String,启动类加载器的搜索范围在java api中,当在api中找到这个String类后便会进行加载,而恶意的java.lang.String将不会被加载,也就是说恶意代码无法伪造身份。若恶意代码试图将自己“混"入java API,比如,一个声明为java.lang.IamHack的类,但由于启动类装载器在api中无法找到该类,它只可能被类路径装载器或用户自定义的类装载器装载,所以与api处在不同的命名空间中,仍然无法获得足够的信任


2.class文件验证

这一过程分为四个阶段

⑴文件结构验证

sun定义的class文件具有特定的结构,以0xCAFEBABE开头标识这是一份java特定的class文件(cafe babe,听说是对barista所作贡献的感谢)。class文件的每一个组成部分都声明了其类型和长度,检验器可以以此计算出正确的class文件总长度,从而判断是否有删减或附加额外的代码

下面是一个接口的16进制标识:
  1. 0000000: cafe babe 0000 0032 0009 0700 0707 0008 .......2........
  2. 0000010: 0100 0564 6f53 7468 0100 0328 2956 0100 ...doSth...()V..
  3. 0000020: 0a53 6f75 7263 6546 696c 6501 0009 446f .SourceFile...Do
  4. 0000030: 6572 2e6a 6176 6101 0015 6575 746f 7069 er.java...eutopi
  5. 0000040: 612f 7365 6375 7269 7479 2f44 6f65 7201 a/security/Doer.
  6. 0000050: 0010 6a61 7661 2f6c 616e 672f 4f62 6a65 ..java/lang/Obje
  7. 0000060: 6374 0601 0001 0002 0000 0000 0001 0401 ct..............
  8. 0000070: 0003 0004 0000 0001 0005 0000 0002 0006 ................
  9. 0000080: 0a .

紧接cafe babe的是虚拟机的主次版本号的16进制标识,然后是常量池中的数据个数,常量次的数据在后侧可以看到,这里包括了类名,方法名等,另外还有字符串和特征符。接下来的对类文件中字段和方法的复杂结构表示。


⑵类型数据语义检查

这一过程需要验证class文件中个组成部分的所属实例是否与声明类型相符合,以及该类型是否符合java语言规定的特定条件,比如final类是否被子类化或是final方法是否被覆写等。另外还有java所有类继承自java.lang.Object,常量池中条目是否合法等。


⑶字节码验证

型数据语义检查并不检验class字节码,字节码的检验将在这个阶段完成。JVM使用的是堆栈体系结构,在使用指令操作数(Java为单字节指令序列)必须将其装入堆栈,JVM规范中又将其称作操作码,每一个操作码后面都跟着一个或多个操作数,为JVM执行操作码时提供额外的数据。JVM依次执行每个操作码,这在JVM内部构成执行线程,每个线程被授予一个由不同栈帧构成的JAVA栈,每一个方法调用都对应内存中的一个栈帧,其中保存了方法中的局部变量和中间结果(保存中间结果的为操作数栈)。

这期间要验证操作数栈中的数据是否合法,方法的调用过程是否使用了合法的参数,局部变量的访问是否被允许(访问必须在初始化之后),字节码验证的验证工作量是比较大的,其中还包括了跳转命令的检查等。经过字节码验证后。可以确保class文件的完整性。


⑷符号引用验证

class文件中对其引用的类,方法,变量等是以文字符号描述的,该描述保证准确定位至唯一的目标。类装载器装载一个类的时候会对其中包含的字符引用作出解析,首先是查找被引用的类,但不一定会加载,因为JVM的延迟加载会确保被引用的类在第一次使用前被加载。若找到了对应的类,则将文字描述替换为直接引用,如指针。JVM会记住这些直接引用,所遇到同样的描述,则直接替换为直接引用,从而避免重复查找。

由于JAVA动态链接的特性,可能会导致二进制不兼容,尽管在改动java文件后的重新编译过程中会检查兼容性,但考虑到在运行时加载的类文件在编译时期并不会被检查,所以需要在运行时执行二进制兼容检查。


3.JVM内置安全特性

在执行期,除了符号引用验证,JVM还会对一些内建的安全特性进行检查,大致如下:
  1. 类型安全的引用转化
  2. 结构化的内存访问(非指针算法)
  3. GC
  4. 数组边界检查
  5. 空引用检查(NullPoint)
强制内存的结构话访问,避免了恶意用户在了解内存分布的情况下通过指针对JVM的内部结构进行破外。当然要了解JVM的内存分布也不是易事。JVM对运行时数据空间的分配是一个黑盒过程,完全由JVM自己决定如何分配,在class中没有任何相关的信息。

字节码检查的局限就是对于那些不经过字节码检查的方法(如本地方法:native method)无法验证其安全性,所以这里采用的是对动态链接库的访问控制,对于那些足有足够可信度的代码才被允许访问本地方法。具体的实现是,由安全管理器来决定代码是否有调用动态链接库的权限,因为调用本地方法必须调用动态链接库。这样一来,不可信的代码将无法通过调用本地方法来绕过字节码检查。


4.安全管理器和java api

我们建立的java application基本上可以说是畅通无阻的,其原因是默认情况下所有JAVA API的操作都是被允许的。但

如果稍加限制一下

新建一个policy(实际上默认既是为read,这点从java.lang.Class中定义getProtectionDomain()方法中可以看出的)


java 代码
  1. grant codeBase "file:///D:/JavaTestCode/security/securitymanager/" {
  2. permission java.io.FilePermission "D:/JavaTestCode/security/securitymanager/*", "read";
  3. };


codeBase指定要限制的类所在目录 :URL
FilePermission 中指定了要保护的文件 :资源名称

然后在运行时以
  1. java -Djava.security.manager -Djava.security.policy=policyURL appName
的形式指定

(也可以通过在java.security中以policy.url.n=policyURL的形式指定)。
java 代码
  1. class TrustlessWriter
  2. {
  3. public static void main(String[] args)throws Exception
  4. {
  5. File data=new File("data.txt");
  6. FileWriter writer=new FileWriter(data);
  7. writer.write("this is a test");
  8. writer.close();
  9. }
  10. }

在控制台输入:
  1. java -Djava.security.manager -Djava.security.policy=myaccess.policy TrustlessWriter


结果将是抛出类似java.security.AccessControlException: access denied (java.io.FilePermission data.txt write)的错误信息

这里需要注意policy的格式

policy file syntax
  1. grant signedBy "signer_names", codeBase "URL",
  2. principal principal_class_name "principal_name",
  3. principal principal_class_name "principal_name",
  4. ... {
  5. permission permission_class_name "target_name", "action",
  6. signedBy "signer_names";
  7. permission permission_class_name "target_name", "action",
  8. signedBy "signer_names";
  9. ...
  10. };

codeBase 需用声明协议类型,若为本地文件话,需以file:声明,FilePermission里面则直接使用目标文件名或通配符


在JAVA2平台安全体系中,访问权限被类型化为对象,也既是说访问权限在Java api中被定义,所有访问权限对象继

承自抽象类java.security.Permission;

所以也可以在代码中启动SecurityManager,并执行检查

java 代码
  1. class TrustlessWriter
  2. {
  3. public static void main(String[] args)throws Exception
  4. {
  5. //SecurityManager sm=new SecurityManager();
  6. FilePermission filePermission=new FilePermission("D:/JavaTestCode/security/securitymanager/data.txt","write");
  7. System.out.println(TrustlessWriter.class.getProtectionDomain());
  8. AccessController.checkPermission(filePermission);//sm.checkPermission(filePermission)
  9. File data=new File("data.txt");
  10. Writer writer=new FileWriter(data,true);
  11. writer.write("hello!");
  12. writer.close();
  13. }
  14. }


此时可省略-Djava.security.manage,执行命令变为:

  1. java -Djava.security.policy=myaccess.policy TrustlessWriter

(AccessController是在JAVA2中引入的,不过考虑到前向兼容,新的平台安全体系中仍然可以使用SecurityManager

来做检查,但SecurityManager的所有check方法均调用AccessController的checkPermission)


关于代码签名和认证

新安全平台中对足够信任度的代码放宽了限制,要获得充分信任须通过代码签名来实现,若我们对某一签名团体足够 信任,比如SUN,那么具有该团体签名的代码将被给予充分信任。一个基本的思路大致为,代码发布者创建私钥/公钥对,然后利用私钥对发布代码进行签名,代码使用方在获得代码发布者提供的公钥后对代码进行验证,确认代码确为该提供者提供以及在发布后未经非法修改。这其中存在一些潜在的危险,既是公钥是否是该代码发布者提供的,恶意用户可能替换掉合法的公钥,这会导致用户将给与恶意用户发布的代码以充分信任,目前的常见做法是通过一些权威的证书机构来发布证书而不是公钥,代码发布者被证书发布机构认证合格后,可以将自己的公钥交付证书发布机构,证书发布机构再通过私钥加密该公钥,从而生成证书序列。这样替换公钥的可能性就变得微乎其微。不过世上无绝对安全之事,通过证书机构发布的证书也不是绝对安全的途径。

对代码进行签名需要将所有class文件打包入jar,然后通过jarsigner对其进行散列计算。

一个简单的示例:

1.首先将CredibleDoer.class打包至 credible.jar:

  1. jar cvf credible.jar eutopia/security/CredibleDoer.class

2.创建别名为credible的密钥对,将其保存在至doerkeys:
  1. keytool -genkeypair -alias credible -keypass douyourwant -keystore doerkeys

3.为credible.jar进行签名:
  1. jarsigner -keystore doerkeys -storepass 111111 -keypass douyourwant credible.jar credible
完成对一个jar文件的签名后,会在jar产生两个文件,此处为credible.SF和credible.DSA

.SF文件保存了一个所有类的列表以及了签名过程中使用的摘要算法,大致如下:

credible.sf
  1. Signature-Version: 1.0
  2. SHA1-Digest-Manifest-Main-Attributes: 9QUCJMHnILftziSD8agLig+iUN8=
  3. Created-By: 1.6.0 (Sun Microsystems Inc.)
  4. SHA1-Digest-Manifest: Z1288OdOqrP+Kstqxv0pS10Je7o=
  5. Name: eutopia/security/CredibleDoer.class
  6. SHA1-Digest: ODGgb1aB9Ht0iVwmfhGSU6pRneo=


DSA文件是一个二进制密匙文件。

验证完整性实验:

现在通过jarsigner -verify credible.jar对该文件进行验证。若文件未经改动,一切正常

若签名后再将TrustlessDoer.class加入credible.jar且不更新签名,那么验证结果将会给出警告:

警告:
此 jar 包含尚未进行完整性检查的未签名条目。

若是替换原有class文件,比如这里替换CredibleDoer.class,将会有类似下面的错误提示:

jarsigner: java.lang.SecurityException: SHA1 digest error for eutopia/security/CredibleDoer.class

通过 keytool -exportcert -file credible.cer -alias credible -keystore doerkeys 可以导出cer正式文件,其中保存了签名的一些基本信息以及公钥

创建密钥对的算法有DiffieHellman,DSA ,RSA, EC可以通过-sigalg <算法名>指定算法,比如:

  1. keytool -sigalg DSA -genkeypair -alias credible -keypass douyourwant -keystore doerkeys

参考:JavaTM Cryptography Architecture API Specification & Reference的Appendix A: Standard Names以及Appendix B: Algorithms


Related Data

深入java虚拟机第二版

Permissions in the JavaTM 2 Standard Edition Development Kit (JDK)

JavaTM Cryptography Architecture API Specification & Reference

Java 安全性架构文档

JavaTM 2 Platform Security Architecture


Default Policy Implementation and Policy File Syntax

Java 授权内幕

J2EE 探索者: 用 JAAS 和 JSSE 实现 Java 安全性
分享到:
评论

相关推荐

    Introduction to JVM Languages

    If you want to build a strong foundation with the JVM and get started with popular modern programming languages, then this book is for you. It begins with a general introduction to JVM and the ...

    推荐一些JVM原理,JVM调优,JVM内存模型,JAVA并发 电子书1

    标题中提到了JVM原理、JVM调优、JVM内存模型和JAVA并发,这些都是Java虚拟机(JVM)相关的核心概念。JVM是运行Java字节码的虚拟计算机,为Java提供了一个跨平台的环境,确保Java程序可以在不同的操作系统上运行而...

    jdk,jvm源码

    Java虚拟机(JVM)是Java程序运行的核心,它负责解释和执行字节码,为Java应用程序提供了一个跨平台的运行环境。JDK(Java Development Kit)包含了开发和运行Java程序所需的所有工具,包括JVM。当我们谈论"jdk,jvm...

    jvm 启动过程 JVM 原理

    Java虚拟机(JVM)是Java程序运行的基础,它是一个抽象的计算机系统,负责执行Java字节码。本文将深入探讨JVM的启动过程及其基本原理。 首先,我们需要理解JVM的基本概念。JVM是Java Virtual Machine的缩写,它是...

    jvm 详细介绍,了解jvm各个组成部分和功能

    例如,“iload”表示加载整数到操作数栈,“anewarray”用于创建数组对象,“iand”表示执行整数位与操作等。这些指令构成了 JVM 执行 Java 字节码的基础。 ##### 2.2 JVM 的 CPU 架构 JVM 的 CPU 架构是其指令...

    JVM图解-JVM指令-JVM原型图.rar

    在这个压缩包中,"JVM图解.png"可能是对JVM内部结构的可视化表示,"JVM图解"可能是一个详细的文档,解释了JVM的工作原理,而"JVM指令手册 中文版"则提供了JVM可执行的所有指令的详细信息。下面,我们将深入探讨JVM的...

    SAP JVM 8.1 64 bits

    SAP JVM 8.1 64位是一个专为SAP系统设计的Java虚拟机,它基于Oracle的Java Development Kit (JDK) 进行优化,以满足SAP应用程序的特定需求。SAP JVM旨在提高性能、可靠性和安全性,同时确保与SAP产品的无缝集成。...

    Java Image Processing Recipes With OpenCV and JVM epub

    Java Image Processing Recipes With OpenCV and JVM 英文epub 本资源转载自网络,如有侵权,请联系上传者或csdn删除 查看此书详细信息请在美国亚马逊官网搜索此书

    jvm memory management and garbage collector

    很久之前就一直在学习JVM,但是一直也没有好好的总结,最近终于有了空闲,将之前学习的内容整理成了一个PPT。PPT也可以在这里下载: https://github.com/hitynsun/docs/tree/master/JVM 也希望大神们可以批评指正...

    JVM中文指令手册.pdf

    JVM(Java Virtual Machine,Java虚拟机)是运行所有Java程序的假想计算机,是Java程序的运行环境,负责执行指令、管理数据、内存、寄存器等,是实现Java跨平台特性的关键部分。JVM指令手册详细记录了JVM的所有操作...

    jvm视频及笔记

    Java虚拟机(JVM)是Java程序运行的核心组件,它负责解释和执行字节码,为开发者提供了跨平台的运行环境。"jvm视频及笔记"这个资源显然是一份全面学习JVM的材料,结合了视频教程和书面笔记,帮助学习者深入理解JVM的...

    jvm-mon基于控制台的JVM监视

    【jvm-mon基于控制台的JVM监视】 `jvm-mon`是一款实用的工具,它允许开发者通过控制台界面实时监控Java虚拟机(JVM)的状态。在Java开发过程中,性能分析是至关重要的,因为良好的性能能提升用户体验,降低服务器...

    (46页完整版)JVM体系结构与GC调优.zip

    46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT...

    狂神说JVM探究.rar

    【狂神说JVM探究】是一份集合了多种格式的学习资料,主要涵盖了Java虚拟机(JVM)的基础知识。这份资料出自B站上的【狂神说Java】系列教程,为快速入门JVM提供了详实的笔记。以下是根据这些资源可能包含的一些关键...

    JVM必知必会

    ### JVM必知必会知识点梳理 #### 1. JVM的定义与层次 Java虚拟机(JVM)具有多重含义: - **一套规范**:即Java虚拟机规范,定义了Java虚拟机应该具有的行为。 - **一种实现**:例如HotSpot、J9、JRockit,它们都是...

    JVM 输出 GC 日志导致 JVM 卡住

    JVM 输出 GC 日志导致 JVM 卡住 JVM 输出 GC 日志导致 JVM 卡住是一个常见的问题,尤其是在高并发和高性能应用中。这个问题的根源在于 JVM 的垃圾回收机制(Garbage Collection,GC),它会在 JVM 运行时周期性地...

    慢慢琢磨jvm 经典

    ### 深入解析JVM:Java虚拟机的精髓与挑战 #### JVM概览与重要性 JVM,即Java Virtual Machine(Java虚拟机),是Java程序员必须掌握的核心技术之一。初学者通常从简单的“HelloWorld”程序开始,逐渐接触更复杂的...

    jvm java虚拟机 调优 马士兵 笔记

    jvm java虚拟机 调优 马士兵 笔记 让你对java虚拟机调优有初步的认识

    Java Image Processing Recipes: With OpenCV and JVM

    Java Image Processing Recipes: With OpenCV and JVM English | ISBN: 1484234642 | 2018 | 379 pages | PDF

    JVM

    Java虚拟机(JVM)是Java编程语言的核心组成部分,它为Java程序提供了运行环境,使得Java代码能够在不同的操作系统上“一次编写,到处运行”。JVM是Java平台的一部分,负责执行字节码,管理内存,垃圾收集,以及提供...

Global site tag (gtag.js) - Google Analytics