密码学及其应用 —— Java中的安全性

1. 简介

        Java是一种广泛使用的编程语言,特别是在企业级解决方案中,比如使用J2EE、JavaBeans等技术。在Web开发领域,Java也有其应用,如客户端的applet和服务器端的Servlets/JSP

1.1 Java的特点

        面向对象:Java是一种面向对象的语言,这意味着它支持类的概念,允许程序员通过类和对象来模拟现实世界中的情况
   
        丰富的API环境:Java提供了一个非常丰富的应用程序编程接口(API),这些API涵盖从基本输入输出到网络编程和图形用户界面(GUI)开发等广泛领域。

        可移植性:Java代码是在Java虚拟机(JVM)上执行的,这意味着编写的Java程序可以在任何安装有相应JVM的操作系统上运行,不受平台的限制。这种“一次编写,到处运行”的特性是Java最大的卖点之一。

1.2 Java的亲戚

        JavaScript:尽管名称相似,但JavaScript与Java实际上关系不大。JavaScript主要用于Web页面的交互设计,在浏览器中执行,是一种脚本语言。它的设计初衷是让网页更加动态和交互性更强。
        JavaCard:这是一个让Java应用能够在小容量设备上运行的平台,比如智能卡。JavaCard技术允许在有限的资源下运行Java应用程序,常用于安全敏感的应用场景,如身份验证、支付系统等。

        Java作为一种成熟且广泛应用的编程语言,其稳定性、功能性和跨平台能力使其成为企业级应用开发和Web开发的热门选择。通过不断更新和社区的支持,Java仍然是当今编程界的重要组成部分。

1.3 Java的安全性

        在Java的设计中,安全性被赋予了极高的重要性。这主要体现在两个方面:

1.3.1 动态类加载

        Java允许从不可信的机器上动态加载类。这提供了一种控制这些类所执行操作的方法,但也带来了安全风险。为了应对这一挑战,Java提供了一套安全管理器和安全策略,通过它们可以控制加载的类能够执行哪些操作,例如文件访问、网络通信等。

1.3.2 Java Applet

        Java Applet是一种可以通过互联网下载并在用户浏览器中运行的Java应用程序。由于Applet是从网络上下载的,它们可能包含恶意代码,因此存在安全风险。Java提供了严格的安全机制来限制Applet的行为,确保它们不能执行有害的操作,如访问本地文件系统或执行任意网络操作。

        在Web客户端中,用户可以通过浏览器执行从服务器端下载的applet。这种机制的主要原则是:

        如果applet包含恶意代码,那么在客户端执行时就可能对用户构成威胁。

        安全问题不仅限于applets,任何从外部获得的程序都可能带来安全风险。

        这些程序可能通过远程方法调用(RMI)连接到服务器。

        程序代码可能来自第三方或外包团队。

        总之,当Web客户端从Web服务器下载并执行applet时,如果这个applet含有恶意指令,就可能对客户端造成安全风险。这也适用于任何外部来源的程序,包括但不限于通过RMI连接的程序或外包代码。这就要求有严格的安全措施来保护用户免受潜在的恶意软件或其他安全威胁的影响。

        Java在设计之初就非常重视安全问题,通过提供一套综合的安全特性和机制来保护系统不受恶意代码的影响,确保Java应用程序和Applet的安全运行。

1.3.3 Java安全性的重要性

        Web用户:当Web用户运行恶意Applet时,可能会遇到病毒、特洛伊木马、蠕虫等各种安全威胁。用户的计算机可能被恶意代码感染,导致个人信息泄露或者计算机功能受损

        Java开发者:Java开发者需要了解并使用Java提供的加密API和安全机制。Java为开发者提供了一套安全相关的工具和功能,帮助他们创建安全的应用程序,这些包括但不限于密钥管理、安全的通信、访问控制等。

        系统管理员:对于系统管理员来说,Applet可能引入新的安全漏洞。管理员必须确保系统的安全配置能够防御这些潜在的威胁,并对系统进行恰当的维护和更新,以保护系统不受Applet或其他Java应用程序的危害。

        商业企业:商业企业在进行商务交易时可能会使用Applet,这些Applet需要进行安全的网络通信。企业必须确保其商务交易的安全性,避免金融信息或客户数据被未经授权的第三方窃取。

        总的来说,Java的安全性对于确保Web应用的完整性、保护用户数据免受侵害以及为商业交易提供安全的环境至关重要。Java提供了一套综合的安全框架和API,但是正确地使用这些工具并保持安全意识是避免安全风险的关键。

2. Java的安全机制

2.1 编译时、运行时的检查机制

        在Java语言中,安全性是一个非常重要的特性,它通过编译时和运行时的各种检查来实现:

2.1.1 编译时的验证

        Java是一种强类型语言,意味着每个变量和表达式的类型都是明确且在编译时已知的,这有助于避免类型错误。

        Java没有指针算术操作,这减少了内存访问错误和潜在的安全漏洞

        未初始化的变量不能使用,这有助于防止使用可能未赋值的变量避免潜在的安全问题或逻辑错误。
        状态变量可以被保护(如使用 private 关键字等),这防止了不恰当的访问和修改,确保了封装性和数据安全。

        提供了 final 关键字来声明变量、方法和类以指明它们不能被更改(变量不可重新赋值,方法不可被覆写,类不可被继承),这有助于保护数据不被修改和维持类设计的不变性。

2.1.2 运行时的验证

        数组访问时会进行边界检查,以防止数组越界错误,这能防止内存损坏和意外访问敏感数据。
        类型转换时进行控制,确保转换是合法的,避免了潜在的类型错误或不一致

        类加载时会进行验证,确保类符合Java语言规范,没有安全问题。这个过程包括验证字节码的格式、检查非法的数据类型等。

        通过这些编译时和运行时的安全检查,Java提供了一个相对安全的编程环境,有助于减少安全漏洞和程序错误。这使得Java成为开发需要高度安全性的应用程序的理想选择,比如银行和电子商务系统。

2.2 编写安全的程序

        在编程时,编写安全的程序是非常重要的第一步。这里有一些建议来提升代码的安全性:

        a. 应尽可能避免使用 protected 修饰符;如果可能,更推荐使用 private 修饰符来提高封装性和安全性。

        b. 避免将敏感的引用暴露给外部;如果需要对外提供数据,应当使用克隆(或复制)的方式来传递值。

        c. 将不应更改的变量或对象声明为 final ,这样它们就不能被再次赋值。

        d. 特别注意与客户端的交互过程,例如要防范SQL注入等安全风险。

        举个例子,对于SQL注入攻击,当请求用户提供用户名(nom)和密码(mdp)进行身份验证时,如果直接将用户输入的值拼接到SQL查询中,攻击者可以输入恶意的SQL代码。

        例如,如果用户名输入为`"Dupond' --"`,那么`--`后面的SQL部分将会被注释掉,这可以让攻击者绕过密码验证。在这个例子中,实际执行的SQL语句会变为:`"select * from user where nom = 'Dupond' --' and mdp= '...'"`,其中`--`后面的部分都被视为注释,因此不会执行。

"select * from user where nom = '" + nom
+ "'and mdp= '" + mdp+ "'"

        为了防范这种攻击,应当使用参数化的查询或者其他方法来安全地处理用户输入,从而防止潜在的SQL注入攻击。

2.3 沙箱

        沙箱是Java虚拟机(JVM)中的一个安全机制,它提供了一个安全的执行环境,阻止潜在危险的访问行为。沙箱机制通过限制代码执行某些操作来保护用户系统的安全,防止恶意软件对系统的破坏。

2.3.1 沙箱受限的危险访问

        a. 用户的本地文件系统:沙箱限制了对用户本地文件系统的访问,以防止恶意代码读取、修改或删除用户文件。

        b. 用户个人信息:沙箱限制了对用户的个人信息的访问,如用户名、电子邮箱地址、计算机配置等,这可以保护用户隐私不被窃取。

        c. 网络连接:沙箱限制了网络连接,禁止未授权的网络通信,防止数据被恶意传输或者恶意软件通过网络传播。

        d. 标记为“危险”的窗口打开:沙箱会阻止打开可能对用户安全构成威胁的窗口

        e. 系统配置的修改:沙箱禁止修改系统配置,避免恶意软件改变系统设置以便其它攻击。

2.3.2 沙箱中的这些限制依赖于以下因素

        a. 类的加载位置:沙箱会检查代码是从哪个位置加载的。通常,从互联网上下载的代码受到的限制比本地代码要多。

        b. 签署类的用户:沙箱会根据签署代码的用户来决定允许执行哪些操作。被信任的开发者签名的代码可能被授予更多权限。

        c. 执行代码的用户:沙箱会检查执行代码的用户身份,不同的用户可能拥有不同的权限级别。

        通过上述机制,Java的沙箱为运行未知或不信任的代码提供了一个较为安全的环境,降低了恶意代码对用户系统造成破坏的风险。

2.3.3 Java Applets与沙箱

        展示了Java Applets的安全机制。Applets是一种可以通过互联网下载并在用户计算机上运行的Java字节码程序。为了保护用户免受恶意代码的影响,Applets运行在Java虚拟机(JVM)的一个安全环境中,即所谓的“沙箱”。

2.3.3.1 Applets的安全机制

        Java的执行环境提供了用于访问控制的机制,这些机制可以自动或按需应用于不同的Java应用程序,例如Applets或远程方法调用(RMI)。具体包括:

        Java Applets:这是一种从外部服务器下载到客户端Web浏览器并在沙箱环境中执行的Java程序。它们通常以字节码形式存在,由JVM解释执行。

        自动访问控制:对于Applets和RMI等,Java虚拟机(JVM)自动提供访问控制,防止这些程序执行危险操作,如访问用户的文件系统或私人信息。
  
        执行环境:JVM提供了一个执行环境,其中包含访问控制的机制,这些机制自动适用于所有的Applets和远程方法调用(RMI)。

        按需访问控制——安全管理器:在某些情况下,开发者或用户可以安装一个安全管理器,这样可以根据具体需求配置安全策略。安全管理器允许更细粒度的控制,可以指定哪些操作是允许的,哪些是禁止的。或者在启动JVM时指定安全参数,以便对Applets的行为进行更精细的控制。

        启动JVM:在启动JVM时,可以通过指定参数来设定安全管理器或安全策略,从而提供一个更加安全的运行环境。

        这些机制结合起来,为Java应用程序提供了一个结构化和可控的安全环境,从而保护用户免受潜在的恶意软件威胁。

2.3.3.2 安全沙箱的工作原理

        当你的Web浏览器下载并执行一个Applet时,它不是在操作系统的普通环境中运行的,而是在一个限制了许多操作权限的沙箱中运行。沙箱机制确保了Applet不会执行某些潜在的危险操作,如:

        访问本地文件系统。

        读取用户的个人信息。

        建立随意的网络连接。

        打开可能会对用户造成安全威胁的窗口。

        修改操作系统的配置。

        这些限制是通过JVM和Java安全模型自动强制实施的,不需要用户手动设置。这为运行不信任的代码提供了一层额外的保护,以防止恶意活动和数据泄露。

        通过这种方式,即使用户从不信任的或未知的来源下载了Applet,系统也能在一定程度上保护用户免受恶意软件的侵害。然而,需要注意的是,随着Web技术的发展,Java Applets已经不再被现代Web浏览器支持。

2.4 Java Applet的运行和安全架构1

        关于Java Applet的运行和安全架构的一个简化图解。主要元素包括客户端(通常是Web浏览器)和服务器端(提供Applet的Web服务器)。具体来说:

2.4.1 服务器端

        Java代码:用Java语言编写的源代码。

        编译器(Compilateur):将Java代码编译成Java字节码。

        Java字节码(Bytecode Java):编译后的代码,可以在任何有Java虚拟机的平台上运行。

2.4.2 客户端

        字节码校验器(Vérificateur de byte code):验证字节码的有效性和安全性,防止恶意代码执行。

        类加载器(Chargeur de classe):负责加载Applet的字节码到Java虚拟机中。

        安全管理器(Managuer de sécurité):控制Applet的执行权限,以防止它执行对系统安全有威胁的操作。

        可执行的Applet:经过安全检查和加载后,Applet在客户端执行

2.4.3 整个过程如下

        开发人员编写Java代码并使用编译器将其转换为Java字节码。

        这些字节码上传到Web服务器上,以便用户可以通过浏览器访问。

         用户的浏览器下载Applet的字节码,然后由客户端的Java虚拟机执行。

        在执行之前,字节码校验器会检查字节码,类加载器会加载Applet,安全管理器则确保执行过程不会危害到用户的计算机。

        客户端的整个区域被标记为“沙箱”,这意味着执行环境有严格的安全限制Applet只能在有限的权限范围内操作,不能进行像修改本地文件或访问网络资源等危险动作。这是为了保护用户的计算机不受恶意软件的影响。

2.5 Java字节码校验器

        Java字节码校验器是Java虚拟机(JVM)的一部分,用于在字节码执行之前确保其安全性和正确性。以下是校验器所做的一些关键分析和校验:

        a. 字节码文件的分析:包括语法分析、数据流分析以及类型的静态验证
   
        b. 保证的属性:

        字节码格式正确:确保字节码遵循Java虚拟机规范的正确格式

        堆栈大小没有超出:验证字节码在执行时不会超过虚拟机栈的最大大小

        字节码指令参数的类型正确:保证每条指令使用的参数类型是正确的,遵守了类型安全

        没有非法类型转换:确保字节码中没有不允许的类型转换操作

        正确使用可见性操作符:如`private`、`public`和`protected`,确保只有在允许的上下文中才访问相应的类成员。

        c. 运行时机制:尽管字节码校验器可以在代码执行前保证很多安全属性,但有些安全机制只能在程序运行时实现,这就需要安全管理器(manageur de sécurité)的介入。
   

        安全管理器在程序运行时提供动态的安全检查,比如检查文件系统访问权限、网络连接权限等。这些结合起来保证了Java应用程序在运行

        综上所述,字节码校验器通过在代码加载到Java虚拟机之前对其进行静态分析,来确保Java应用程序的安全性和稳定性。如果校验器发现字节码中有潜在的安全问题或不符合规范的代码,这些字节码将不会被执行。而安全管理器则负责在程序运行时提供动态的安全性检查

2.6 类加载器(Chargeur de classe)

        在Java中,类加载器(Chargeur de classe)是用来保护执行环境完整性的关键组件,确保不会重新定义系统类,从而防止安全机制被绕过。以下是类加载器的一些主要功能和它们对安全性的影响:

        保护执行环境的完整性:类加载器确保系统类不会被重新定义,这有助于避免破坏Java运行时环境的完整性和安全性。

        禁止安全机制的绕过:通过不允许重新定义系统,类加载器可以阻止恶意代码绕过Java安全模型,例如禁止加载可能会覆盖关键安全功能的自定义类

        网络加载的类保留自己的命名空间:从网络加载的类在自己的命名空间中运行,这意味着它们不会与系统类冲突或替换系统类。

        提供的库位于特定位置:Java提供的库和用户自定义的库存放在特定的位置,这通常由CLASSPATH环境变量指定。

        搜索机制始于CLASSPATH:类加载器在加载类时会先从CLASSPATH指定的位置开始搜索,这有助于确保首先加载正确和安全的类,再加载其他类。

        通过上述机制,类加载器在Java安全架构中扮演着关键角色,确保了代码在加载和执行时的安全性。通过限制对系统类的重定义,Java提高了运行时的安全性,防止了不可信代码对关键系统组件的潜在破坏。

2.7 安全管理器(Manageur de sécurité)

        Java的安全管理器(Manageur de sécurité)是一个在运行时对潜在危险方法调用进行动态检查的组件。它可以预防一些可能会危害用户系统安全的行为

        动态验证潜在危险的方法调用:这些方法可能涉及访问本地文件系统、网络连接、用户环境变量等。

        调整安全策略:可以通过修改安全管理器来定制哪些方法被认为是危险的,从而控制程序的行为。

        安全管理器的实例化:通常实例化为`java.lang.SecurityManager`类或其子类的一个对象。

        拒绝访问时的处理:如果安全管理器判定某个操作不安全,会抛出一个未经检查的异常`java.security.AccessControlException`。

        综上所述,安全管理器为Java提供了一种机制,可以在运行时对程序执行的操作进行安全性审查,并允许开发者定制安全策略,以满足不同的安全需求。当尝试执行未经授权的操作时,安全管理器将抛出异常,从而阻止潜在的危险操作。

2.8 Java安全架构2

        Java安全架构2提供了一种基于代码签名的差异化访问权限控制机制,它使得访问控制更为灵活和细粒度。

2.8.1 架构模型讲解

        这个图展示了Java Web应用中关于客户端和服务器之间如何通过签名的Applet来管理权限的流程。

        Web服务器:服务器存储了经过签名的Java字节码(Byte code Java)。这里的签名证明了代码的来源是经过验证的,可以提供一定程度的信任

        签名的Applet:这是一个Java程序(通常是小型的、可以嵌入网页的应用程序),它已经被开发者签名,表明它是由一个已知且可信的实体发布的

        客户端:用户的计算机或设备上运行的客户端软件,通常是Web浏览器

        字节码校验器(Vérificateur de byte code):在客户端验证Applet字节码的有效性,确保它没有被篡改且安全可执行。

        类加载器(Chargeur de classe):负责加载Applet类到Java虚拟机中

        安全管理器(Managuer de sécurité):基于已定义的权限(permissions),如读取和写入权限(read, write),决定是否允许Applet执行特定的操作。

        可执行文件(executable):表示经过校验和权限确认后,Applet已准备好执行。

        这个图解说明了Java在执行代码之前进行了一系列的安全检查,确保执行的代码是可信的,且不会对用户的计算机造成危害。通过这种方式,Java提供了一个相对安全的环境来运行可能来自不安全来源的代码。

2.8.2 根据签名的不同访问权限

        系统可以根据代码签名来分配不同的访问权限,允许签名后的代码执行特定的操作。

2.8.3 控制机制的原理

        拥有数字签名的`.jar`文件:这意味着代码已经被认证,是由可信任的源头发布

        包含特定访问权限的签名者公钥的本地文件:系统会有一个存储有签名者公钥的文件,这些签名者被授予了特定的访问权限。

        描述基于签名授予访问权限的权限文件(安全策略):一个定义了哪些签名代码能够获得什么样权限的文件,它描述了安全策略

2.8.4 根据签名指定的访问权限

        这意味着,根据代码的签名者和安全策略的具体内容,系统可以精确地控制哪些操作是被允许的。

        通过这样的安全架构,Java允许开发者和系统管理员创建详细的安全策略对不同来源的代码块实施不同级别的权限。这不仅有助于防止恶意代码的执行,还能保护用户的数据安全。

2.9 Java安全策略

        Java安全策略通常通过权限文件来描述,这个文件规定了基于代码签名的各种访问权限。这里提及的概念包括安全域,它定义了特定的签名者或代码源的权限。以下是如何在安全策略文件中配置安全域和赋予特定权限的一个例子:

keystore "/chemin/du/fichier/de/cles";
grant signedBy "unsignataire" {
permission java.net.SocketPermission "unserv.fr", "connect";
permission java.io.FilePermission "/un/chemin/-", "write";
permission java.io.FilePermission "C:\\users\\truc\\*", "read";
permission java.io.FilePermission "${user.home}${/}*", "read,write";
};

        密钥库路径:通过`keystore`指令指定了密钥库文件的路径,这个文件包含了公钥和私钥。

        授权签名者: grant signedBy "unsignataire" 这一行表示授予签名者为`"unsignataire"`的实体某些权限。

        套接字连接权限:通过`permission java.net.SocketPermission "unserv.fr", "connect"`,允许这个签名者的代码创建到`"unserv.fr"`的网络连接。

        文件写入权限:`permission java.io.FilePermission "/un/chemin/-", "write"`表示授权对指定路径的文件进行写操作。

        文件读取权限:`permission java.io.FilePermission "C:\\users\\truc\\*", "read"`指定了在特定用户目录下所有文件的读权限。

        用户家目录的读写权限:最后一行通过动态的系统属性`${user.home}`和文件分隔符`${/}`来定义对当前用户主目录下所有文件的读写权限。

        这个安全策略的配置样例展示了如何为签名代码指定详细的权限,这些权限可以非常具体,涵盖了从网络访问到本地文件操作的多个层面。这样的配置确保了只有被信任的代码能够执行敏感操作,从而提高了Java应用的安全性。

2.10 Java中的安全管理器

        Java中的安全管理器(gestionnaire de sécurité)可以通过不同方式选择和安装,根据执行上下文(如浏览器)或者直接在Java虚拟机(JVM)启动时指定。以下是设置安全管理器的一些选项:

        由执行上下文安装:在某些情况下,如当使用浏览器运行Java Applet时,安全管理器通常会自动被设置。

        通过JVM选项设置:可以在启动JVM时通过`java -Djava.security.manager=MonSM Classe`选项来指定一个自定义的安全管理器。这里的`MonSM`代表自定义安全管理器的类名,`Classe`代表主类。

        在程序中设置:通过程序代码`System.setSecurityManager(...)`来设置。注意,设置安全管理器的代码需要有相应的权限。

        默认情况:默认情况下,如果一个应用是通过CLASSPATH中的类直接启动的,它可能不会被安全管理器控制。

        对远程代码加载的警告:如果应用程序在没有安全管理器的情况下加载远程代码,可能会带来安全风险,因为这些代码可能未受到适当的安全检查。

        因此,在运行可能加载和执行远程代码的Java应用程序时,要非常小心,确保一个有效的安全管理器被正确设置,以监控和限制潜在危险操作,确保系统的安全。

3. 安全功能的API

        Java加密架构(JCA)和Java加密扩展(JCE)是Java提供的用于安全功能的API。

3.1 加密机制

        加密机制的目的是确保数据的保密性、完整性和消息发送者的身份认证。下面是实现这些目标的几种常见的加密技术:

        加密(chiffrement):将可理解的文本(也称为明文转换为无法理解的密文,以防止未授权的第三方读取和理解数据的内容。

        完整性校验函数(fonction de vérification d'intégrité):保证数据在传输或存储过程中没有被篡改,从而确保数据的完整性。

        数字签名(signature numérique):通过数字签名技术,可以验证消息的签名者身份,并保证消息自签名之后没有被篡改。

        这些机制是信息安全的基石,使得在数字世界中的通信和数据存储可以达到类似于现实世界中信封密封、签名确认和文件完好无损的效果。

3.2 JCA(Java Cryptography Architecture)

        这是Java的一个加密API,它提供了以下功能和服务:
        哈希函数:可以生成数据的摘要或哈希值。
        数字签名:用于验证数据的完整性和来源的真实性。
        密钥管理:生成、存储和管理加密密钥。
        证书操作:用于处理公钥证书,例如验证证书链。
        包路径:JCA的功能通过`java.security`包及其子包提供。
        扩展性:JCA可以通过添加“提供者”(providers)来扩展,提供者可以提供新的算法实现。

3.3 JCE(Java Cryptography Extension)

        JCE是JCA的扩展,主要添加了支持加密算法的功能,例如:
        对称加密算法:如DES。
        非对称加密算法:如Diffie-Hellman密钥交换协议。
        提供者:JCE的一个常见提供者是SunJCE。
        包路径:JCE的功能通过`javax.crypto`包及其子包提供。

        通过这些API,Java应用程序可以实现各种安全相关的功能,如加密通信、文件加密、身份验证和授权等。JCA和JCE为开发人员提供了一个相对简单且统一的接口来访问加密功能,同时也允许使用第三方加密技术提供者来增强应用程序的安全性。

3.4 哈希函数的定义Fonction de vérification d’intégrité

        一个哈希函数用于计算文本的固定大小的“加密摘要”(résumé cryptographique)。

3.4.1 属性

        不可逆性:不能从摘要中恢复原文(单向函数)
        唯一性:不可能找到两个文本具有相同的摘要

3.4.2 标准算法

        MD5(由Rivest设计):对任意长度的文本生成128位的摘要。

        SHA(Secure Hash Algorithm):对任意长度的文本生成160位的摘要。这些算法在信息安全领域至关重要,用于验证数据的完整性和身份认证过程中。

3.4.3 JCA中使用哈希函数计算消息的加密摘

        在Java加密架构(JCA)中,使用哈希函数来计算消息的加密摘要是一种常见的操作。以下是计算消息摘要的步骤:

        a. 将字符串转换成字节流:首先将消息字符串转换成字节流(byte数组),以便进行加密处理。

byte[] tampon = message.getBytes()

        b. 初始化哈希算法:选择并初始化所需的哈希算法(例如SHA或MD5)。

MessageDigest algo = MessageDigest.getInstance("SHA");

        c. 填充消息到缓冲区:将消息的字节流提供给哈希算法,以进行加密处理

algo.update(tampon);

        d. 生成摘要:最后,执行加密处理,生成消息的加密摘要

byte[] resume = algo.digest();

        完整性验证:发送者和接收者可以使用相同的哈希函数计算消息的摘要。接收者通过比较自己计算的摘要和发送者提供的摘要来验证消息的完整性。如果两个摘要相等,则说明消息在传输过程中未被篡改,完整性得到了保证。

3.5 数字签名

3.5.1 定义

        确保发送者身份和消息完整性

3.5.2 数字签名的过程

3.5.2.1 数字签名过程

        明文(文本):这是原始信息,需要被发送者签名。

        哈希(Hacher):使用哈希函数对明文进行哈希处理,生成一个摘要(résumé)。

        加密(Chiffrer):使用发送者的私钥(clé privée)对摘要进行加密,生成签名。

        签名后的文本(texte signé):将签名附加到原始文本上,形成签名后的文本,这个过程保证了信息的不可否认性和完整性。

3.5.2.2 签名验证过程

        签名后的文本:这是收到的、包含签名的信息。

        解密(Déchiffrer):使用发送者的公钥(clé publique)对签名进行解密,得到摘要。

        哈希(Hacher):再次使用相同的哈希函数对收到的文本(不包括签名部分)进行哈希处理。

        比较(比较运算符):比较解密后得到的摘要与重新哈希得到的摘要是否相同。

        如果两个摘要相同,这验证了信息自签名后未被更改,并确认了信息是由持有匹配私钥的发送者签名的。如果不同,则表明信息可能被篡改或签名不是由声称的发送者创建的。这个过程提供了信息的验证和发送者身份的验证。

3.5.3 数字签名的步骤

        在Java加密架构(JCA)中,数字签名的一个重要步骤是生成一对公私钥。以下是使用DSA算法生成公私钥对的一个示例:

3.5.3.1 步骤一:生成密钥对
3.5.3.1.1 创建密钥对生成器

        `KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");`

        这行代码初始化了一个密钥对生成器,指定了使用DSA算法。

3.5.3.1.2 初始化密钥对生成器

        `kpg.initialize(1024);` 这行代码设置了密钥的大小。这里指定了1024位的密钥长度,这是数字签名算法(DSA)的一个常见密钥大小,旨在提供足够的安全性。

3.5.3.1.3 生成密钥对

         KeyPair kp = kpg.generateKeyPair();` 这行代码生成了公私钥对。其中,`kp.getPublic()`和`kp.getPrivate()`可以分别用来获取生成的公钥和私钥。

        生成的公钥可以安全地公开,用于验证签名,而私钥必须保密,只用于生成签名。

3.5.3.2 步骤二:对数据进行数字签名

        在Java加密架构(JCA)中,对数据进行数字签名的步骤如下:

3.5.3.2.1 初始化签名对象

        首先,创建一个`Signature`对象,指定使用`SHA1withDSA`算法。这个算法组合意味着你将使用SHA-1哈希函数和DSA签名算法。

Signature sig = Signature.getInstance("SHA1withDSA");
3.5.3.2.2 设置私钥

        然后,从之前生成的密钥对中获取私钥,并初始化`Signature`对象以进行签名。

PrivateKey priv = kp.getPrivate();
sig.initSign(priv);
3.5.3.2.3 填充数据

        使用update方法将要签名的数据(以字节数组`byte[]`形式提供)添加到签名对象中。

sig.update(message);
3.5.3.2.4 生成签名

        最后,调用sign方法计算签名,它会返回一个表示签名的字节数组。

byte[] signature = sig.sign();

        得到的签名可以和原始数据一起发送给接收者。接收者可以使用发送者的公钥来验证签名的有效性,这既验证了数据的完整性,也确认了发送者的身份。这种方法是保护数据传输安全性的有效手段,防止数据被篡改和验证通信双方的身份。

3.5.3.2 步骤三:验证数字签名

        在Java加密架构(JCA)中,验证数字签名的过程如下:

3.5.3.2.1 创建签名对象

        使用与签名者相同的算法创建一个`Signature`对象。在这个例子中,我们使用的是`SHA1withDSA`算法,即SHA-1哈希算法配合DSA签名算法。

Signature sig = Signature.getInstance("SHA1withDSA");
3.5.3.2.2 指定公钥

        指定签名者的公钥。这个公钥用于验证签名的真实性。

PublicKey pub = kp.getPublic();
sig.initVerify(pub);
3.5.3.2.3 验证签名

        使用update方法将接收到的数据(message)添加到`Signature`对象中。然后,调用verify方法来验证与数据关联的签名是否有效。

   sig.update(message);
   if (sig.verify(signature)) {
       System.out.println("消息完整无误"); // Message intègre
   } else {
       System.out.println("警告,消息可能已被篡改!"); // Attention, message corrompu !
   }

        如果verify方法返回true,说明消息是完整的,签名验证成功,可以信任消息内容。如果返回`false`,则消息可能已被篡改,应当小心对待这些数据。这个验证过程确保了数据的完整性和发送者的身份验证。

4. 加密技术

4.1 对称加密技术

4.1.1 基本概念

        对称加密(chiffrement symétrique):加密和解密使用相同的密钥,这个密钥称为秘密密钥。对称加密的优点是加解密速度快,但它的主要挑战在于如何安全地交换密钥,因为发送方和接收方必须共享相同的密钥,如果密钥在交换过程中被截获,加密通信的安全性就会受到威胁。

        对称加密中密钥交换问题是对称加密的主要难点。需要确保密钥的交换过程安全,避免密钥被第三方截获。

4.1.2 对称加密AES算法

        AES(高级加密标准)进行对称加密和解密的基本步骤。在对称加密中,加密和解密使用的是相同的密钥。让我们逐步分析:

4.1.2.1 生成密钥
KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecretKey aesKey = keygen.generateKey();

        这两行代码初始化了一个`KeyGenerator`对象,指定使用AES算法。`generateKey`方法用于生成一个密钥(`SecretKey`),这个密钥将用于后续的加密和解密过程。

4.1.2.2 创建Cipher对象
Cipher aesCipher;
aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

        这里首先声明了一个`Cipher`对象,然后通过`getInstance`方法创建了一个具体的`Cipher`实例。参数 AES/ECB/PKCS5Padding 指定了算法/工作模式/填充模式:

        AES:指定使用AES加密算法

        ECB:电子密码本(Electronic Codebook)模式,是最简单的加密模式,直接将明文分组加密。但它不推荐用于长度超过一个分组的数据加密,因为它不能很好地保护数据模式。

        PKCS5Padding:指定填充模式,用于处理不足一个完整加密分组的数据。

4.1.2.3 初始化Cipher对象并加密明文
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] cleartext = "This is just an example".getBytes();
byte[] ciphertext = aesCipher.doFinal(cleartext);

        init`方法用于初始化Cipher对象,指定是加密模式(`ENCRYPT_MODE`)并使用之前生成的密钥(`aesKey`)。之后,将字符串转换成字节序列,并用 doFinal 方法进行加密,得到加密后的字节序列 ciphertext 。

4.1.2.4 初始化Cipher对象并解密密文
aesCipher.init(Cipher.DECRYPT_MODE, aesKey);
byte[] cleartext1 = aesCipher.doFinal(ciphertext);

        再次通过 init 方法初始化 Cipher 对象,这次是为了解密( DECRYPT_MODE ),使用相同的密钥。doFinal 方法用于解密先前加密的 ciphertext ,得到原始的明文字节序列 cleartext1 。

        总的来说,这段代码展示了使用AES算法进行加密和解密的整个流程,包括密钥生成、Cipher对象的创建和初始化、明文的加密以及密文的解密。使用相同的密钥进行加密和解密是对称加密的典型特征。

4.2 非对称加密技术

4.2.1 基本概念

        非对称加密(chiffrement asymétrique):加密和解密使用不同的密钥。加密使用公钥,解密使用私钥。非对称加密通常用于安全地交换对称加密的密钥,也用于数字签名。其挑战在于非对称加密相比对称加密计算量大,速度慢,因此通常在需要安全交换密钥或验证身份时使用。

        非对称加密中使用公钥和私钥的管理。公钥可以公开,用于加密信息和验证签名,而私钥必须保密,用于解密信息和创建数字签名。非对称加密的计算更为复杂,需要使用复杂的算法如RSA或ECC。

4.2.2 非对称加密的解释

        非对称加密是一种加密方式,它使用一对密钥:公钥和私钥。在非对称加密的情境中,任何人都可以使用公钥进行加密,但只有拥有对应私钥的人才能解密。下面是一个示例,说明Alice如何使用Bob的公钥发送一封加密的邮件给Bob:

        a. Bob的密钥准备

        Bob生成一对密钥:一个公钥和一个私钥。
        Bob保留私钥,不与任何人分享。
        Bob将公钥公开,或者提供给需要给他加密信息的人。

        b. Alice准备加密邮件

        Alice想要发送一封保密邮件给Bob。
        Alice获取Bob的公钥。这可以通过公钥基础设施(PKI)、邮件、网站下载等方式实现。

        c. 使用公钥加密

        Alice使用Bob的公钥对邮件进行加密。一旦使用Bob的公钥加密后,邮件就只能被拥有对应私钥的Bob解密。

        d.Bob解密邮件

        Bob收到Alice发送的加密邮件。
        Bob使用他的私钥对邮件进行解密。由于私钥仅由Bob持有,因此只有Bob能够解读Alice的邮件。

        e. 安全通信实现

        通过这种方式,即使加密邮件在传输过程中被拦截,没有Bob的私钥,拦截者也无法解密邮件内容。
        这确保了信息的机密性和安全性。

        非对称加密的典型应用包括电子邮件加密、数字签名和安全套接层(SSL)加密通信。相比对称加密,非对称加密的一个优点是它解决了密钥分配问题,使得在不安全的通道上也能安全地交换加密信息。然而,非对称加密通常比对称加密要慢,因此它们经常结合使用:非对称加密用于安全地交换对称加密的密钥,然后使用对称加密来加速数据传输的加密过程。

4.2.3 RSA非对称加密算法

        RSA非对称加密算法来加密和解密数据。RSA是一种广泛使用的加密技术,它依赖于一对密钥:公钥和私钥。公钥用于加密数据,而私钥用于解密数据。下面是代码的逐行解释:

4.2.3.1 生成密钥对
KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
KeyPair kp = keygen.generateKeyPair();
PublicKey pubKey = kp.getPublic();
PrivateKey privKey = kp.getPrivate();

        使用`KeyPairGenerator`类的`getInstance`方法初始化一个RSA密钥对生成器。

        调用`generateKeyPair`方法生成一对密钥,其中包括一个公钥和一个私钥。

        分别通过getPublic和`getPrivate`方法获取公钥和私钥。

4.2.3.2 创建并初始化加密Cipher
Cipher rsaCipher;
rsaCipher = Cipher.getInstance("RSA");
rsaCipher.init(Cipher.ENCRYPT_MODE, pubKey);

        声明`Cipher`对象`rsaCipher`。

        使用Cipher类的`getInstance`方法创建一个RSA加密器。

        通过调用init方法,使用公钥初始化`rsaCipher`为加密模式。

4.2.3.3 加密明文
byte[] cleartext = "I love you, Alice !!".getBytes();
byte[] ciphertext = rsaCipher.doFinal(cleartext);

        将字符串转换为字节序列,准备加密。

        使用doFinal方法对明文进行加密,生成加密后的数据(密文)。

4.2.3.4 初始化解密Cipher并解密密文
rsaCipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] cleartext1 = rsaCipher.doFinal(ciphertext);

        使用私钥,重新初始化`rsaCipher`为解密模式。

        使用doFinal方法对密文进行解密,恢复为原始的明文数据。

        通过这个过程,数据使用公钥进行加密,确保只有拥有对应私钥的接收者能够解密和阅读原始数据。这个特性使得RSA非常适合在不安全的网络环境中安全地传输敏感信息。

4.3 数字证书和证书颁发机构(CA,Certification Authority)

        在使用非对称加密技术进行数据交换时,的确存在一个潜在的问题:任何人都可以声称自己拥有某个公钥,从而冒充其身份接收不本属于他们的数据。为了解决这个问题,引入了数字证书和证书颁发机构(CA,Certification Authority)的概念,旨在建立对公钥所有者身份的信任。

4.3.1 问题的本质

        非对称加密确保了只有持有相应私钥的人能解密用公钥加密的信息,但它本身不解决公钥的身份验证问题。如果攻击者可以轻易地将自己的公钥传给别人并声称这是另一个人的公钥,那么他们就可以拦截和解密原本发送给那个人的加密信息。

4.3.2 数字证书

        数字证书是一种电子认证,用来证明公钥的所有权。它包含了公钥所有者的信息(如姓名和电子邮件地址)、公钥本身、证书颁发机构(CA)的签名,以及其他用于验证证书所有者身份的信息。当一个证书由一个受信任的CA签名时,它提供了对公钥所有者身份的验证。

4.3.2.1 X.509标准

        数字证书,特别是遵循X.509标准的证书,是公钥基础设施(PKI)中的一个关键组成部分,用于在网络上安全地分配公钥。X.509是一种非常普遍的数字证书标准,最初于1988年发布。它定义了证书的格式,包括证书应包含的信息。X.509证书主要内容包括:

4.3.2.1.1 证书颁发机构(CA)的身份

        这是颁发证书的机构或个人的名称和其他识别信息。证书颁发机构(CA)是被信任的第三方,负责验证证书申请者的身份,并为其颁发证书。

4.3.2.1.2 证书所有者的身份

        这包含了证书所有者的名称和其他身份信息,如电子邮件地址、组织名称等。证书所有者通常是证书中公钥的持有者。

4.3.2.1.3 证书所有者的公钥

        这是证书主体(即证书所有者)的公钥。公钥用于非对称加密和数字签名验证。

4.3.2.1.4 证书的有效期

        包括证书的开始有效日期和结束有效日期。这定义了证书的有效时间窗口,在此期间证书被认为是有效的。

4.3.2.1.5 证书的序列号

        每个证书都有一个唯一的序列号,CA用它来识别证书。

4.3.2.1.6 数字签名

        证书颁发机构使用其私钥对证书进行数字签名。这个签名保证了证书的完整性和真实性,接收方可以使用CA的公钥来验证这个签名。

4.3.2.1.7 签名算法

        证书中还包含用于数字签名的算法信息,如使用的散列函数和加密算法(例如,SHA-256和RSA)。

        证书的这些信息共同工作,提供了一种机制,通过它接收者可以验证公钥的真实归属,并确保它未被篡改。数字证书因此在确保网络通信的安全性方面起着至关重要的作用。

4.3.3 证书颁发机构(CA)

        CA是一个受信任的第三方机构,负责颁发、签名和管理数字证书。CA通过严格的身份验证过程确保申请者是公钥的合法拥有者后,会签发一个包含申请者公钥和身份信息的数字证书。这个证书可以被任何人用来验证公钥所有者的身份。

4.3.4 如何工作

        证书请求:当一个实体(比如一个网站)希望获得一个数字证书时,它会生成一对密钥(公钥和私钥),并将公钥和一些身份信息发送给CA作为证书签名请求(CSR)。

        验证和签发:CA验证实体的身份信息。如果信息验证成功,CA用自己的私钥对该实体的公钥和身份信息进行签名,生成一个数字证书。

        使用证书:实体可以将其数字证书公开地提供给任何人。当其他人接收到通过该公钥加密的信息时,他们可以使用CA的公钥来验证数字证书的有效性,从而确信公钥确实属于声明的身份。

        通过这种机制,即使在不安全的环境中,人们也可以有信心地使用公钥进行加密通信,因为他们可以验证公钥所有者的身份。这大大减少了“中间人攻击”(MITM)的风险,其中攻击者试图拦截或篡改通信。

5. Java身份验证和授权服务(JAAS)API

        在Java平台上,安全性始终是一个核心考虑。Java2平台引入了一种基于代码来源和签名者的权限控制模型,以确保只有经过验证的代码能执行特定操作

        而JAAS(Java Authentication and Authorization Service)提供了一套机制来保护系统免受用户的潜在恶意行为影响,它通过为用户分配权限来实现这一点下面详细介绍这两种安全控制机制:

5.1 Java2的权限模型

        Java2安全模型允许开发者根据代码的来源(例如,来自哪个网站或本地)和签名者(代码被哪个实体签名)来授予代码执行权限这种模型侧重于根据代码的可信度来决定它可以执行哪些操作。例如,来自受信任源的代码可能会被授予文件访问权限,而来自不明来源的代码则被限制只能执行最基本的操作。

5.2 JAAS:认证和授权

        JAAS扩展了Java的安全功能,引入了基于用户的认证和授权机制。它使得Java应用不仅能控制代码可以执行哪些操作,还能根据用户身份来授予权限。

        认证:JAAS通过所谓的登录模块来验证用户身份。这些模块可以连接到不同的身份验证服务,如LDAP、数据库或其他自定义服务。成功认证后,用户将获得一个或多个虚拟身份,这些身份反映了用户在不同上下文中的角色和权限。

        授权:一旦用户被成功认证,系统就可以根据用户的身份(或角色)来授权用户执行特定的操作。这种授权通过检查安全管理器中的权限来实施,只有当用户拥有执行操作所需的权限时,才允许操作执行。

5.3 配置灵活性

        JAAS提供了高度的配置灵活性允许在不改变应用程序代码的情况下,通过配置文件来定义安全策略。这意味着可以在部署阶段或运行时动态调整应用程序的安全行为,使得应用能适应不同的安全需求。

        总的来说,Java的这些安全机制提供了一种强大的方式来保护系统免受未授权代码和用户的潜在威胁,同时也为满足不同的安全需求提供了灵活性。通过结合使用基于代码的安全控制和基于用户的认证授权机制,Java应用可以实现高度安全且可配置的安全策略,以保护资源不受滥用

5.4 JAAS的全局架构示意图

        JAAS(Java Authentication and Authorization Service)的全局架构示意图,它展示了如何在Java应用中实现认证和授权机制。

        应用程序(Application):这是主体应用程序,它需要对用户进行认证和授权。它与安全管理器(SecurityManager)交互以实现安全控制

        安全管理器(SecurityManager):这是Java安全架构的一部分,用于对应用程序的安全策略进行管理和执行。它根据配置文件(例如`jaas.conf`和`login.policy`)来确定是否允许执行某个操作。

        配置文件(jaas.conf):这是JAAS配置文件,指定了认证模块(如SampleLoginModule`\)的信息。这个文件定义了应用程序使用的登录模块,以及这些模块的配置选项。

        登录模块(SampleLoginModule):这是一个实现了JAAS的LoginModule接口的样例类。登录模块负责实现用户认证过程,它会与用户存储系统(如数据库、LDAP服务器等)交互,验证用户提供的身份凭证。

        认证(Authentification):指的是确认用户身份的过程。当用户尝试登录应用程序时,认证过程会确定用户是否为其声称的身份。

        授权文件(login.policy):这是包含授权策略的文件。授权决定了认证后的用户能执行哪些操作。这个文件定义了哪些角色或用户具有执行特定代码段的权限

        授权(Autorisation):这指的是一旦用户通过认证,系统允许他们执行的操作。授权通常是基于用户的角色或组进行的,不同的角色可能有不同的权限。

        通过这个架构图,我们可以看出,JAAS通过从应用程序代码中分离出安全性配置来实现灵活性,使得开发者无需修改应用程序代码,就能通过修改配置文件来改变认证和授权策略。这种方法既提高了安全性,也增加了可维护性和灵活性

5.5 用JAAS进行用户认证的最小示例

        这段代码是一个Java应用程序中使用JAAS(Java Authentication and Authorization Service)进行用户认证的最小示例。以下是代码的解释:

LoginContext lc = new LoginContext("Sample");

        创建 LoginContext 对象,这是JAAS中用于用户认证的核心类。 Sample 是在JAAS配置文件(例如`jaas.conf`)中定义的登录模块的名称。

try{
    lc.login();
} catch (LoginException e){
    // 认证失败
}

        调用 LoginContext 的 login 方法来进行用户认证。如果认证成功, login 方法正常执行;如果认证失败,则抛 LoginException 异常。

Subject subject = lc.getSubject();

        如果认证成功,通过 getSubject 方法可以获取代表已认证用户的 Subject 对象。Subject 可能包括用户的凭证和相关的安全信息。

Subject.doAs(subject, new CriticalAction());

        这行代码使用了 Subject 对象来执行一个重要的操作。 doAs 方法接收两个参数:一个Subject 和一个实现了 PrivilegedAction 接口的对象。这表示 CriticalAction 中的代码将在被认证用户的安全上下文中执行,即只有在用户通过认证后, CriticalAction 才会被执行

        JAAS配置文件 jaas.conf:

Sample {
    SampleLoginModule required debug=true;
};

        这是JAAS配置文件的一个示例,它定义了一个名为 Sample 的登录模块。在这里,SampleLoginModule 是指定用于认证的类required 关键字表示这个登录模块是必需的,debug=true 提供了额外的调试信息。这个文件告诉JAAS框架使用指定的 SampleLoginModule 类来处理名为 Sample 的认证请求。

        整体上,这个示例展示了如何在Java程序中使用JAAS来执行用户认证,并在认证成功后执行一些特定的操作。这是建立Java应用程序安全的基础步骤之一。

5.6 序列图

        一个序列图,展示了在Java应用中使用JAAS框架进行用户认证的流程。下面是各部分的中文解释:

        用户(图中的小人图标)开始身份认证过程。

        Main:表示主要的执行类,在这个类中创建了 LoginContext 的实例。

        lc:LoginContext :LoginContext类的实例,它是处理登录和认证的核心。

        configuration JAAS jaas.conf`:指向JAAS的配置文件,其中定义了认证的策略和登录模块

        ->SampleLoginModule:指出`LoginContext`将使用配置文件中指定的`SampleLoginModule`来进行认证。

        login():LoginContext类的login方法被调用,启动认证过程。

        saisie info:表示用户需要输入信息,比如用户名和密码。

        demande ident.:表示系统请求用户的身份认证信息。

        Subject:一旦认证成功,系统将创建一个`Subject`实例,其中包含了用户的身份凭证和安全信息。

        `lc = new LoginContext("Sample");

        lc.login();`

        是这个过程在Java代码中的表示,它创建了一个 LoginContext 对象,并调用它的 login 方法以开始认证过程。

        整个认证过程是这样的:用户触发认证过程,Main类创建`LoginContext`实例,该实例根据`jaas.conf`配置文件使用`SampleLoginModule`执行认证。

        用户输入的凭据被`SampleLoginModule`验证。

        如果认证成功,`Subject`会被创建并填充用户信息,应用程序之后可以基于这个`Subject`进行授权判断。

5.7 LoginModule 接口

        在Java认证和授权服务(JAAS)框架中,LoginModule接口扮演着关键角色。它定义了认证技术的接口,任何实现了这个接口的类都可以用于验证用户的身份。以下是一些由com.sun.security.auth.module 包提供的`LoginModule`实现的例子及其用途:

5.7.1 由JAAS提供的 LoginModule 类

        UnixLoginModule:用于在Unix系统上认证用户。它利用操作系统的用户账户系统进行认证。

        NTLoginModule:用于在Windows NT系统上进行用户认证。类似于UnixLoginModule,它也是依据操作系统的账户信息来验证用户。

        Krb5LoginModule:用于实现Kerberos协议的认证。Kerberos是一种网络认证协议,它基于“票据”(Ticket)和“密钥”(Key)来进行用户的安全认证。

        KeystoreLoginModule:用于使用Java密钥库(Keystore)中的信息来认证用户。密钥库是加密密钥和证书的数据库。

5.7.2 自定义和第三方 LoginModule

        除了这些预定义的模块,也可以根据具体需求实现自定义的`LoginModule`,或者购买第三方提供的模块。自定义的`LoginModule`可以用于支持特定的认证方法,如:

        使用数据库存储的用户名和密码进行认证。

        使用文件系统中的文件,例如存储有用户凭证的文件进行认证

        使用一些外部服务,比如OAuth提供商进行认证。

        为了实现一个自定义的 LoginModule ,开发者需要实现 LoginModule 接口,并定义如何验证用户身份的逻辑。

        这个模块需要能够读取和处理存储在数据库、文件或其他任何地方的用户凭证。自定义的`LoginModule`可以通过JAAS配置文件(`jaas.conf`)被引入到应用程序中,并由`LoginContext`在运行时调用。

        在自定义`LoginModule`时,通常要处理以下几个关键步骤:

        初始化:接收来自`LoginContext`的回调信息。

        认证:实施实际的身份验证逻辑。

        提交:如果认证成功,将用户信息保存到`Subject`中。

        回滚:如果认证过程失败,清理状态。

        创建安全且高效的自定义认证模块需要对安全性有深入的理解,确保所有敏感信息(如密码)都以安全的方式处理。

5.8 授权

        授权是认证之后的一个重要步骤。在用户通过认证之后,系统需要确定该用户有权限执行哪些操作。这里是授权的基本原则和流程:

5.8.1 用户特定的权限

        授权过程确保只有拥有相应权限的用户才能执行特定的操作。这意味着不同的用户可能根据其角色和权限获得对不同资源的访问权限。

5.8.2 安全策略文件

        权限通常在安全策略文件中定义,这是一个特殊的文件,用于声明哪些代码(基于代码源、代码签名者或执行代码的`Subject`)有权执行哪些操作

5.8.3 实现 PrivilegedAction 的类

        执行敏感操作的代码通常放在实现了 PrivilegedAction 接口的类中。 run方法包含了需要特权执行的代码。

5.8.4 使用 Subject.doAs 方法

        在认证之后,Subject对象代表了一个已认证的用户。通过调用`Subject.doAs(Subject s, PrivilegedAction a)`方法,可以在特定用户的安全上下文中执行代码。这个方法接受两个参数:一个`Subject`和一个`PrivilegedAction`。当调用`doAs`时,它会执行`PrivilegedAction`对象的`run`方法。

5.8.5 PrivilegedAction`的`run`方法

        这个方法是`PrivilegedAction`接口中的唯一方法,它包含了需要以提升权限执行的代码。当`Subject.doAs`被调用时,`run`方法会被执行。

5.8.6 安全管理器的验证

        在执行 PrivilegedAction 的 run 方法时,如果访问了受保护的资源或执行了敏感操作,Java的安全管理器(SecurityManager)将会介入。安全管理器会根据安全策略文件(也就是权限文件)中定义的规则来检查是否允许执行该操作。

        通过这种方式,授权机制使得Java应用程序可以精细地控制不同用户对系统资源的访问,从而增强了应用程序的安全性。它确保了只有拥有适当权限的用户才能执行特定的操作,从而防止了未授权的访问和潜在的滥用。

5.8.7 授权的示例

        假设有一个名为 login.policy 的文件,它包含了授权信息:

grant Principal SamplePrincipal "toto" {
    permission java.util.PropertyPermission "java.home", "read";
    permission java.util.PropertyPermission "user.home", "read";
    permission java.io.FilePermission "/tmp/foo.txt", "write,read";
};

        grant 语句定义了授予特定主体(在这个例子中是名为`toto`的`SamplePrincipal`)的权限。

        permission 条目列出了这个主体拥有的具体权限,包括读取系统属性和对特定文件进行读写操作的权限。

5.8.8 使用安全管理器调用应用

        在命令行中使用安全管理器启动Java程序时,可以指定安全策略文件和配置文件:

-Djava.security.manager -Djava.security.policy=login.policy 

-Djava.security.auth.login.config=jaas.conf Main

        -Djava.security.manager 指定了要使用Java安全管理器。

        -Djava.security.policy=login.policy 指定了安全策略文件的位置,这里是`login.policy`。

        -Djava.security.auth.login.config=jaas.conf 指定了JAAS配置文件的位置。

        当这些系统属性被设置后,Java虚拟机将按照 login.policy 文件中指定的策略来执行安全检查,同时JAAS配置将决定认证策略。

        整体而言,授权机制确保了只有得到适当授权的用户才能执行特定的操作,这对于维护系统的安全性至关重要。

6. 总结

        Java提供了一个全面的安全框架,以确保程序的安全运行。Java虚拟机(JVM)和Java平台的几个安全特性包括:

6.1 虚拟机(VM)

        Java虚拟机是设计用来安全地执行程序代码的。通过在虚拟机内部运行Java代码,可以提供一个隔离层,防止潜在的恶意代码对主机系统造成影响。

6.2 模型执行和隔离

        Java实现了一种模型执行过程,其中每个应用程序都在自己的虚拟机实例中运行,与其他应用程序相互隔离。

6.3 验证器(Verifier)和类加载器(Class Loader)

        字节码验证器:在类加载到JVM之前,字节码验证器检查Java字节码,确保它不会违反JVM的安全约束。
        类加载器:在类被加载到JVM时,类加载器可以将安全策略应用于它们,确保类的来源已经过验证。

6.4 运行时安全性检查

        数组边界检查:Java在运行时对数组进行边界检查,防止数组越界,这可以避免内存损坏等安全漏洞。

        访问控制:Java在动态解析方法调用之后进行访问控制检查,包括检查调用堆栈来确定是否有权限执行操作。

6.5 代码签名和证书

        Java支持代码签名,无论是使用证书还是不使用证书。签名的代码可以通过Java的安全框架进行验证,以确保代码的来源和完整性。

6.6 加密API

        Java加密架构(JCA)和Java加密扩展(JCE):Java提供了丰富的API来支持加密和解密操作,这些API构成了Java加密架构。

6.7 认证和授权API

        Java认证和授权服务(JAAS):JAAS提供了API用于用户认证和授权,支持如前所述的登录模块和权限模型。

        通过以上的安全特性,Java提供了一个全面的安全架构,允许开发者构建安全性更高的应用程序,这些程序可以保护自己不受恶意软件的侵害,同时也保护用户数据不被未授权访问。

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

思诺学长-刘竞泽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值