原文:
有关 StAX 的更多信息,请参见:
- Java 社区进程页面.
- W3C 推荐 可扩展标记语言(XML)1.0
- XML 信息集
- jcp.org 上的 JAXB 规范:JSR-222 Java XML 绑定架构(JAXB)
- W3C 推荐 文档对象模型
- SAX 简单 XML API
- DOM 文档对象模型
- W3C 推荐 XML 中的命名空间
有关使用 StAX 的一些有用文章,请参见:
- Jeff Ryan, StAX 是否应该成为您的 XML 工具箱中的一部分?
- Elliott Rusty Harold, StAX 简介
原文:
本课程重点介绍了 JAXP 1.5 中引入的新属性。
JAXP 1.5 被添加到了 7u40 和 JDK 8 版本中。你可以从下载当前的JDK 8 快照。
原文:
JAXP 安全处理功能对 XML 处理器施加资源限制,以抵御某些类型的拒绝服务攻击。 但是,它并不限制获取外部资源的方式,这在尝试安全处理 XML 文档时也是有用的。 当前的 JAXP 实现支持特定于实现的属性,可用于强制执行此类限制,但需要一种标准方法来实现。
JAXP 1.5 添加了三个新属性以及它们对应的系统属性,允许用户指定可以或不可以允许的外部连接类型。属性值是协议列表。 JAXP 处理器通过将协议与列表中的协议进行匹配来检查给定的外部连接是否被允许。 如果连接在列表中,则处理器将尝试建立连接,否则将拒绝连接。
JAXP 1.5 已经集成到 7u40 和 JDK8 中。
原文:
XML、Schema 和 XSLT 标准支持以下需要外部资源的构造。JDK XML 处理器的默认行为是建立连接并按照指定的方式获取外部资源。
- 外部 DTD:引用外部文档类型定义(DTD),示例:
- 外部实体引用:引用外部数据,语法:
通用实体引用如下:
- 外部参数实体,语法 。例如:
- XInclude:在 XML 文档中包含外部信息集
- 使用 属性、 和 元素引用 XML Schema 组件。示例:
- 使用 或 元素合并样式表:语法:
- xml-stylesheet 处理指令:用于在 xml 文档中包含样式表,语法:
- XSLT 函数:用于访问外部 XML 文档中的节点。例如,。
原文:
JAXP 1.5 定义了三个新属性,用于调节 XML 处理器是否解析上述外部资源。这些属性是:
这些 API 属性具有相应的系统属性和 jaxp.properties。
名称:
定义:限制对外部 DTD、外部实体引用到指定协议的访问。
值:参见属性的值
默认值:,允许连接到所有协议。
系统属性:
名称:
定义:限制对由属性、Import 和 Include 元素设置的外部引用协议的访问。
值:参见属性的值
默认值:,允许连接到所有协议。
系统属性:
名称:
定义:限制对由样式表处理指令、文档函数、Import 和 Include 元素设置的外部引用协议的访问。
值:参见属性的值
默认值:,允许连接到所有协议。
系统属性:
这些属性可以在中指定,以定义所有使用 Java Runtime 的应用程序的行为。格式为。例如:
属性名称与系统属性相同:、和。
所有属性的值格式相同。
值:由逗号分隔的协议列表。协议是 URI 的 scheme 部分,或者在 JAR 协议的情况下,由冒号分隔的"jar"加上 scheme 部分。协议定义为:
其中 alpha = a-z 和 A-Z。
以及 JAR 协议:
协议不区分大小写。值中由定义的任何空格将被忽略。协议的示例包括、、。
默认值:默认值是实现特定的。在 JAXP 1.5 RI、Java SE 7u40 和 Java SE 8 中,默认值为,授予所有协议的权限。
授予所有访问:关键字授予所有协议的权限。例如,在中设置将允许系统像以前一样工作,无限制地访问外部 DTD 和实体引用。
拒绝任何访问:空字符串,即"",表示不授予任何协议权限。例如,在中设置将指示 JAXP 处理器拒绝任何外部连接。
原文:
(FSP)是包括 DOM、SAX、Schema Validation、XSLT 和 XPath 在内的 XML 处理器的必需功能。当设置为时,建议实现启用由上述新属性定义的访问限制。为了兼容性,尽管对于 DOM、SAX 和 Schema Validation,默认情况下 FSP 为 true,但 JAXP 1.5 不会启用新的限制。
对于 JDK 8,建议将新的属性在 FSP 被明确设置时设置为空字符串。这仅在通过 API 设置 FSP 时才会发生,例如。尽管对于 DOM、SAX 和 Schema Validation,默认情况下 FSP 为 true,但 JDK 8 并不将其视为“明确”设置,因此默认情况下不会设置限制。
在文件中指定的属性会影响 JDK 或 JRE 的所有调用,并将覆盖其默认值,或者可能已经由 FEATURE_SECURE_PROCESSING 设置的值。
当设置系统属性时,将仅影响一个调用,并将覆盖默认设置或在 jaxp.properties 中设置的设置,或者可能已经由 FEATURE_SECURE_PROCESSING 设置的设置。
通过 JAXP 工厂或指定的 JAXP 属性优先于系统属性,文件以及。
新的 JAXP 属性在以下情况下对其试图限制的相关构造没有影响:
- 当存在解析器并且解析器返回的源不为 null 时。这适用于可能设置在 SAX 和 DOM 解析器上的实体解析器,StAX 解析器上的 XML 解析器,SchemaFactory 上的 LSResourceResolver,验证器或 ValidatorHandler,或者转换器上的 URIResolver。
- 当通过调用的方法显式创建模式时。
- 当不需要外部资源时。例如,以下功能/属性由参考实现支持,并可用于指示处理器不加载外部 DTD 或解析外部实体。
原文:
在尝试连接之前,将首先检查 JAXP 属性,无论是否存在。这意味着即使授予权限,连接也可能被阻止。例如,如果 JAXP 属性被设置为禁止 http 协议,它们将有效地阻止任何连接尝试,即使应用程序具有。
为了限制连接,可以被视为处于较低级别。在评估 JAXP 属性之后,权限将被检查。例如,如果一个应用程序没有,即使 JAXP 属性被设置为允许 http 连接,也会抛出。
当存在时,被设置为 true。这种行为不会启用新的限制。
原文:
以下表格显示了 JDK 中新属性的默认值和行为。
(a) 设置 FSP 意味着明确使用 JAXP 工厂的 方法设置 FEATURE_SECURE_PROCESSING。
(b) 7u40 和 JDK8 之间唯一的行为差异是,在 7u40 中设置 FSP 不会更改 属性,但在 JDK8 中会将值设置为空字符串。在 JDK8 中,设置 FSP 被视为选择加入。
© 表中从左到右的顺序反映了覆盖顺序。例如,如果通过 API 设置了 属性,则会覆盖其他可能已通过其他方式设置的属性。
译文:
本节重点介绍了 JAXP 1.5 中引入的新属性。
只有处理不受信任的 XML 内容的应用程序才需要限制获取外部资源。不处理不受信任内容的内部系统和应用程序不需要关注新的限制或进行任何更改。自 7u40 和 JDK8 默认没有对此类限制的要求,应用程序在升级到 7u40 和 JDK8 时不会出现行为变化。
对于处理不受信任的 XML 输入、Schema 或样式表的应用程序,如果已经存在安全措施,比如启用 Java 安全管理器仅授予受信任的外部连接,或者使用解析器解析实体,则不需要 JAXP 1.5 中添加的新功能。
然而,JAXP 1.5 确实为没有安全管理器运行的系统和应用程序提供了直接的保护。对于这类应用程序,可以考虑使用下面详细描述的新功能来进行限制。
当改变代码可行时,通过 JAXP 工厂或解析器设置新属性是启用限制的最佳方式。属性可以通过以下接口设置:
以下是一个将 DOM 解析器限制为仅本地连接的外部 DTD 的示例:
当代码更改可行,并且对于新开发,建议设置新属性如上所示。通过这种方式设置属性,应用程序可以确保无论部署到较旧还是较新版本的 JDK,或者通过系统属性或设置属性,都能保持所需的行为。
如果改变代码不可行,系统属性可能会有用。
如果希望为整个 JDK/JRE 调用设置限制,可以在命令行上设置系统属性;如果仅需要部分应用程序,可以在该部分之前设置系统属性,然后在之后清除。例如,以下代码展示了如何使用系统属性:
是一个普通的配置文件。它位于,其中 是 JRE 安装目录,例如,。
可通过将以下行添加到 jaxp.properties 文件来设置外部访问限制:
设置此项后,所有 JDK/JRE 的调用将遵守加载外部样式表的限制。
对于不希望允许 XML 处理器进行任何外部连接的系统,此功能可能很有用,此时,所有三个属性可以设置为,例如,仅文件。
原文:
由于这些属性是当前版本的新功能,建议应用程序捕获适合接口的异常,例如,在以下示例中捕获 SAXException。在旧版本上,应用程序可能正常工作,例如,示例代码包含以下方法,用于检测是否使用支持新属性的 JDK 版本或 JAXP 实现运行示例:
如果由于新属性设置的限制而拒绝访问外部资源,则将以以下格式抛出异常并带有错误信息:
例如,如果由于限制只允许使用 http 协议而拒绝获取外部 DTD,如下所示:,并且解析器解析包含对的外部引用的 XML 文件,则错误消息将如下所示:
原文:
StAX、JSR 173 的规范尚不支持新属性。然而,在 JAXP 的上下文中,StAX 确实包括对这些属性的支持。设置新属性类似于 SAX 或 DOM,但通过 XMLInputFactory,如下所示:
存在于 StAX、JSR 173 规范中指定的属性和特性将优先于新的 JAXP 属性。例如,当 SupportDTD 属性设置为 false 时,将导致程序在输入文件包含 DTD 之前无法解析时抛出异常。对于使用 SupportDTD 属性禁用 DTD 的应用程序,新属性的添加不会产生影响。
原文:
JAXP 1.5 提供了新的属性,让用户可以控制获取外部资源。使用新属性与其他现有属性相同,只是这些属性与相应的系统属性和一起提供,以便它们可以用于系统范围的限制或权限。
原文:
欲了解更多信息,请参阅以下资源:
- JSR 206 JAXP 1.5 maintenance review
- 7u40 Release Notes
- JDK 8 API and Documentation
- JDK 7 API and Documentation
- JEP 185
原文:
XML 处理有时可能是一个消耗大量内存的操作。应用程序,特别是那些接受来自不受信任来源的 XML、XSD 和 XSL 的应用程序,应该通过使用 JDK 提供的 JAXP 处理限制来防范过度的内存消耗。
开发人员应该评估他们应用程序的需求和运行环境,以确定系统配置的可接受限制,并相应地设置这些限制。与大小相关的限制可用于防止处理畸形的 XML 源时消耗大量内存,而将允许应用程序在可接受水平下控制内存消耗。
在本教程中,您将了解这些限制,并学习如何正确使用它们。
原文:
以下列表描述了 JDK 支持的 JAXP XML 处理限制。这些限制可以通过工厂 API、系统属性和文件指定。
这些属性自 JDK 5.0 和 6 起被引入,并继续为向后兼容性而受支持。
可以在文件中指定系统属性,以定义 JDK 或 JRE 的所有调用的行为。格式为。例如:
原文:
(FSP)功能对包括 DOM、SAX、模式验证、XSLT 和 XPath 在内的 XML 处理器是必需的。当 FSP 设置为时,建议的默认限制将被强制执行。将 FSP 设置为不会改变这些限制。
当 Java 安全管理器存在时,FSP 被设置为 true 且无法关闭。因此,建议的默认限制将被强制执行。
在文件中指定的属性会影响 JDK 和 JRE 的所有调用,并将覆盖它们的默认值,或者可能已被 FSP 设置的值。
系统属性在设置时会影响 JDK 和 JRE 的调用,并覆盖默认设置或者在中设置的值,或者可能已被 FSP 设置的值。
通过 JAXP 工厂或指定的 JAXP 属性优先于系统属性,文件以及。
原文:
评估包括在系统级别考虑应用程序可用的内存量,是否接受和处理来自不受信任来源的 XML、XSD 或 XSL 源,以及在应用程序级别考虑是否使用某些构造(如 DTD)。
XML 处理可能非常消耗内存。允许消耗的内存量取决于特定环境中应用程序的要求。必须防止处理格式不正确的 XML 数据消耗过多内存。
默认限制通常设置为允许大多数应用程序的合法 XML 输入,并允许小型硬件系统(如 PC)的内存使用。建议将限制设置为可能的最小值,以便在消耗大量内存之前捕获任何格式不正确的输入。
这些限制是相关的,但并非完全冗余。您应为所有限制设置适当的值:通常限制应设置为比默认值小得多的值。
例如,可以设置和来防止过多的实体引用。但是当扩展和实体大小的确切组合未知时,可以作为整体控制。同样,虽然控制替换文本的总大小,但如果文本是一个非常大的 XML 块,会限制文本中可以出现的节点总数,并防止系统过载。
为帮助您分析应设置的限制值,提供了一个名为的特殊属性。以下代码片段显示了使用该属性的示例:
查看示例以获取有关下载示例代码的更多信息。
当程序在 W3C MathML 3.0 中运行时,将打印出以下表格:
在此示例中,实体引用的总数,或实体扩展,为 1417;默认限制为 64000。所有实体的总大小为 55425;默认限制为 。在解析所有引用后,最大的参数实体是 ,长度为 7303;默认限制为 。
如果这是应用程序预计要处理的最大文件,请建议将限制设置为较小的数字。例如, 设置为 2000, 设置为 , 设置为 10000。
限制可以像其他 JAXP 属性一样设置。它们可以通过工厂方法或解析器设置:
以下示例显示了如何使用 设置限制:
如果更改代码不可行,系统属性可能很有用。
要为整个 JDK 或 JRE 的调用设置限制,请在命令行上设置系统属性。要仅为应用程序的一部分设置限制,可以在该部分之前设置系统属性,并在之后清除。以下代码显示了如何使用系统属性:
请注意,属性的值应为整数。如果输入的值不包含可解析的整数,将抛出 ;请参阅方法 。
查看 示例 以获取有关下载示例代码的更多信息。
文件是一个配置文件。通常位于 ,其中 是 JRE 安装目录,例如,[安装目录路径]/jdk8/jre。
可通过向 文件添加以下行来设置限制:
请注意,属性名称与系统属性相同,并具有前缀 。属性的值应为整数。如果输入的值不包含可解析的整数,将抛出 ;请参阅方法 。
当在文件中设置属性时,所有 JDK 和 JRE 的调用都将遵守限制。
原文:
建议应用程序在设置新属性时捕获异常,以便应用程序在不支持这些属性的旧版本上正常工作。例如,可下载的示例代码包含以下方法,,用于检测示例是否在支持属性的 JDK 版本上运行:
当输入文件包含导致超出限制异常的结构时,应用程序可以检查错误代码以确定失败的性质。以下错误代码适用于这些限制:
- : JAXP00010001
- : JAXP00010002
- : JAXP00010003
- : JAXP00010004
- : JAXP00010005
- : JAXP00010006
- : JAXP00010007
错误代码的格式如下:
因此,代码 JAXP00010001 代表了 JAXP 基本解析器安全限制。
原文:
StAX,JSR 173,不支持 FSP。然而,JDK 中的 StAX 实现支持新的限制属性及其对应的系统属性。这意味着,虽然没有 FSP 来开启和关闭限制,但描述的限制和系统属性的工作方式完全相同。
为了兼容性,StAX 特定属性总是在新的 JAXP 限制之前生效。例如,将属性设置为 false 会导致在输入文件包含引用时抛出异常。因此,对于使用属性禁用 DTD 的应用程序,新限制的添加不会产生影响。
原文:
你可以下载包含两个 Java 应用程序文件和以及一个包含示例 xml 文件的目录的文件。
要运行示例,请解压文件,编译,并在命令行上执行以下操作:
原文:
Java 远程方法调用(RMI)系统允许在一个 Java 虚拟机中运行的对象调用另一个 Java 虚拟机中运行的对象的方法。RMI 提供了 Java 编程语言编写的程序之间的远程通信。
注意: 如果你要连接到一个现有的 IDL 程序,应该使用 Java IDL 而不是 RMI。
本教程简要介绍了 RMI 系统,然后演示了一个完整的客户端/服务器示例,该示例利用了 RMI 的独特功能,在运行时加载和执行用户定义的任务。示例中的服务器实现了一个通用的计算引擎,客户端用它来计算 的值。
描述了 RMI 系统并列出了其优势。此外,本节介绍了典型的 RMI 应用程序,由服务器和客户端组成,并介绍了重要术语。
演示了计算引擎服务器的代码。本节将教你如何设计和实现一个 RMI 服务器。
着眼于一个可能的计算引擎客户端,并用它来说明 RMI 客户端的重要特性。
展示了如何编译和运行计算引擎服务器及其客户端。
原文:
RMI 应用程序通常由两个独立的程序组成,一个服务器和一个客户端。典型的服务器程序创建一些远程对象,使这些对象的引用可访问,并等待客户端调用这些对象的方法。典型的客户端程序获取服务器上一个或多个远程对象的远程引用,然后调用这些对象的方法。RMI 提供了服务器和客户端进行通信和传递信息的机制。这样的应用有时被称为分布式对象应用。
分布式对象应用需要执行以下操作:
- 定位远程对象。 应用程序可以使用各种机制获取对远程对象的引用。例如,应用程序可以使用 RMI 的简单命名设施,即 RMI 注册表,注册其远程对象。另外,应用程序可以将远程对象引用作为其他远程调用的一部分传递和返回。
- 与远程对象通信。 远程对象之间的通信细节由 RMI 处理。对于程序员来说,远程通信看起来类似于常规的 Java 方法调用。
- 加载传递的对象的类定义。 因为 RMI 允许对象来回传递,它提供了加载对象的类定义以及传输对象数据的机制。
以下插图描述了一个使用 RMI 注册表获取远程对象引用的 RMI 分布式应用程序。服务器调用注册表将名称与远程对象关联(或绑定)。客户端在服务器的注册表中按名称查找远程对象,然后调用其方法。插图还显示了 RMI 系统使用现有的 Web 服务器在需要时从服务器到客户端和从客户端到服务器加载类定义的过程。
RMI 的一个核心和独特特性是,如果接收方的 Java 虚拟机中未定义类的定义,它可以下载对象类的定义。一个对象的所有类型和行为,以前仅在单个 Java 虚拟机中可用,可以传输到另一个可能是远程的 Java 虚拟机。RMI 通过其实际类传递对象,因此当它们被发送到另一个 Java 虚拟机时,对象的行为不会改变。这种能力使得可以将新类型和行为引入到远程 Java 虚拟机中,从而动态扩展应用程序的行为。本教程中的计算引擎示例使用了这种能力来向分布式程序引入新行为。
与任何其他 Java 应用程序一样,使用 Java RMI 构建的分布式应用程序由接口和类组成。接口声明方法。类实现接口中声明的方法,并且可能还声明其他方法。在分布式应用程序中,一些实现可能驻留在一些 Java 虚拟机中,而另一些则不在。具有可以在 Java 虚拟机之间调用的方法的对象称为远程对象。
通过实现远程接口,对象变成远程对象,具有以下特征:
- 一个远程接口扩展接口。
- 接口的每个方法在其子句中声明,除了任何特定于应用程序的异常。
当对象从一个 Java 虚拟机传递到另一个 Java 虚拟机时,RMI 会将远程对象与非远程对象区别对待。RMI 不会在接收 Java 虚拟机中复制实现对象,而是传递一个远程对象的远程存根。存根充当远程对象的本地代表或代理,并且基本上是客户端的远程引用。客户端在本地存根上调用方法,本地存根负责在远程对象上执行方法调用。
一个远程对象的存根实现了远程对象实现的相同一组远程接口。这个属性使得一个存根可以被转换为远程对象实现的任何接口。然而,只有在远程接口中定义的方法才能从接收 Java 虚拟机中调用。
使用 RMI 开发分布式应用程序涉及以下一般步骤:
- 设计和实现分布式应用程序的组件。
- 编译源代码。
- 使类可网络访问。
- 启动应用程序。
设计和实现应用程序组件
首先,确定您的应用程序架构,包括哪些组件是本地对象,哪些组件是可远程访问的。这一步包括:
- 定义远程接口。 远程接口指定客户端可以远程调用的方法。客户端编程针对远程接口,而不是针对这些接口的实现类。这些接口的设计包括确定将用作这些方法的参数和返回值的对象类型。如果这些接口或类中的任何一个尚不存在,您也需要定义它们。
- 实现远程对象。 远程对象必须实现一个或多个远程接口。远程对象类可能包括其他仅在本地可用的接口和方法的实现。如果要将任何本地类用作这些方法的参数或返回值,那么它们也必须被实现。
- 实现客户端。 使用远程对象的客户端可以在定义远程接口之后的任何时间实现,包括在部署远程对象之后。
编译源代码
与任何 Java 程序一样,您使用编译器来编译源文件。源文件包含远程接口的声明、它们的实现、任何其他服务器类以及客户端类。
注意: 在 Java 平台标准版 5.0 之前的版本中,需要通过使用编译器来构建存根类,但现在不再需要这一步骤。
使类能够在网络中访问
在这一步中,您需要使某些类定义能够在网络中访问,例如远程接口及其关联类型的定义,以及需要下载到客户端或服务器的类的定义。通常通过 Web 服务器使类定义能够在网络中访问。
启动应用程序
启动应用程序包括运行 RMI 远程对象注册表、服务器和客户端。
本节的其余部分将介绍创建计算引擎所使用的步骤。
本教程专注于一个简单但强大的分布式应用程序,称为计算引擎。计算引擎是服务器上的一个远程对象,它接收来自客户端的任务,运行这些任务,并返回任何结果。这些任务在运行服务器的机器上执行。这种类型的分布式应用程序可以让多台客户端机器利用特别强大或具有专门硬件的机器。
计算引擎的新颖之处在于它运行的任务不需要在编写或启动计算引擎时定义。可以随时创建新类型的任务,然后将其交给计算引擎运行。任务的唯一要求是其类实现特定接口。RMI 系统可以将执行任务所需的代码下载到计算引擎中。然后,计算引擎在运行它的机器上利用资源运行任务。
执行任意任务的能力是由 Java 平台的动态特性实现的,通过 RMI 扩展到网络。RMI 动态加载任务代码到计算引擎的 Java 虚拟机中,并在没有实现任务的类的先验知识的情况下运行任务。这种具有动态下载代码能力的应用程序通常被称为基于行为的应用程序。这些应用程序通常需要完整的代理启用基础设施。在 Java 平台上,这些应用程序是分布式计算的基本机制之一。
原文:
计算引擎服务器接受来自客户端的任务,运行这些任务,并返回任何结果。服务器代码由一个接口和一个类组成。接口定义了可以从客户端调用的方法。实质上,接口定义了客户端对远程对象的视图。类提供了实现。
设计一个远程接口
这一部分解释了接口,它提供了客户端和服务器之间的连接。您还将了解支持此通信的 RMI API。
实现一个远程接口
这一部分探讨了实现接口的类,从而实现了一个远程对象。这个类还提供了组成服务器程序的其余代码,包括一个创建远程对象实例的方法,将其注册到 RMI 注册表,并设置安全管理器。
原文:
计算引擎的核心是一种协议,使得任务可以提交到计算引擎,计算引擎可以运行这些任务,并将这些任务的结果返回给客户端。这个协议在支持计算引擎的接口中表达。该协议的远程通信在下图中有所体现。
每个接口包含一个方法。计算引擎的远程接口允许任务提交到引擎。客户端接口定义了计算引擎如何执行提交的任务。
接口定义了远程访问部分,即计算引擎本身。这里是接口的源代码:
通过扩展接口,接口将自身标识为一个可以从另一个 Java 虚拟机中调用其方法的接口。实现这个接口的任何对象都可以是一个远程对象。
作为远程接口的成员,方法是一个远程方法。因此,该方法必须被定义为能够抛出的方法。这个异常是由 RMI 系统从远程方法调用中抛出的,用于指示通信失败或协议错误。是一个受检异常,因此任何调用远程方法的代码都需要通过捕获它或在其子句中声明来处理这个异常。
计算引擎所需的第二个接口是接口,它是接口中方法的参数类型。接口定义了计算引擎和需要执行的工作之间的接口,提供了开始工作的方式。这里是接口的源代码:
接口定义了一个方法,该方法没有参数,也不会抛出异常。因为该接口没有扩展,所以在该接口中的方法不需要在子句中列出。
接口有一个类型参数,代表任务计算的结果类型。该接口的方法返回计算的结果,因此其返回类型是。
接口的方法反过来返回传递给它的实例的执行结果。因此,方法有自己的类型参数,将其自己的返回类型与传递的实例的结果类型关联起来。
RMI 使用 Java 对象序列化机制在 Java 虚拟机之间按值传输对象。要使对象被视为可序列化,其类必须实现标记接口。因此,实现接口的类必须也实现,任务结果所使用的对象的类也必须实现。
只要它们是类型的实现,不同类型的任务可以由对象运行。实现这个接口的类可以包含任务计算所需的任何数据以及计算所需的任何其他方法。
这就是 RMI 如何使这个简单的计算引擎成为可能。因为 RMI 可以假定对象是用 Java 编程语言编写的,之前未知于计算引擎的对象的实现会根据需要通过 RMI 下载到计算引擎的 Java 虚拟机中。这种能力使得计算引擎的客户端能够定义新的任务类型,而无需将代码明确安装在该机器上。
由类实现的计算引擎实现了接口,通过调用其方法,使不同的任务可以提交给它。这些任务使用任务的方法的实现来运行,并将结果返回给远程客户端。
原文:
本节讨论实现计算引擎类的任务。一般来说,实现远程接口的类至少应该执行以下操作:
- 声明正在实现的远程接口。
- 为每个远程对象定义构造函数。
- 为远程接口中的每个远程方法提供实现。
RMI 服务器程序需要创建初始远程对象并将其导出到 RMI 运行时,使其可用于接收传入的远程调用。此设置过程可以封装在远程对象实现类本身的方法中,也可以完全包含在另一个类中。设置过程应执行以下操作:
- 创建并安装安全管理器
- 创建并导出一个或多个远程对象。
- 至少在 RMI 注册表(或其他命名服务,如通过 Java 命名和目录接口访问的服务)中注册一个远程对象,用于引导目的。
计算引擎的完整实现如下。类实现了远程接口,并包括用于设置计算引擎的方法。以下是类的源代码:
以下各节讨论计算引擎实现的每个组件。
计算引擎的实现类声明如下:
此声明说明该类实现了远程接口,因此可以用作远程对象。
类定义了一个远程对象实现类,该类实现了一个单独的远程接口,没有其他接口。类还包含两个仅可在本地调用的可执行程序元素。其中一个元素是用于实例的构造函数。另一个元素是用于创建实例并使其对客户端可用的方法。
类有一个不带参数的构造函数。构造函数的代码如下:
此构造函数只调用了超类构造函数,即类的无参数构造函数。尽管即使在构造函数中省略了超类构造函数,超类构造函数也会被调用,但为了清晰起见,还是包含在内。
远程对象的类为远程接口中指定的每个远程方法提供实现。接口包含一个单独的远程方法,,其实现如下:
此方法实现了远程对象与其客户端之间的协议。每个客户端都向提供一个具有接口的特定实现的对象的方法。执行每个客户端的任务,并将任务的方法的结果直接返回给客户端。
远程方法的参数或返回值几乎可以是任何类型,包括本地对象、远程对象和基本数据类型。更准确地说,只要实体是基本数据类型、远程对象或可序列化对象的实例,就可以将任何类型的实体传递给远程方法或从远程方法传递出来,这意味着它实现了接口。
一些对象类型不符合这些标准,因此无法传递给远程方法或从远程方法返回。其中大多数对象,如线程或文件描述符,封装的信息只在单个地址空间内有意义。许多核心类,包括和包中的类,实现了接口。
关于如何传递参数和返回值的规则如下:
- 远程对象本质上是通过引用传递的。远程对象引用是一个存根,是一个客户端代理,实现了远程对象实现的完整远程接口集。
- 本地对象通过对象序列化进行复制传递。默认情况下,除了标记为或的字段外,所有字段都会被复制。可以按类覆盖默认序列化行为。
通过引用传递远程对象意味着通过远程方法调用对对象状态所做的任何更改都会反映在原始远程对象中。当传递远程对象时,只有接收者可用的是远程接口。在实现类中定义的方法或类实现的非远程接口中定义的任何方法对接收者不可用。
例如,如果您要传递对类实例的引用,则接收方只能访问计算引擎的方法。该接收方将看不到构造函数、其方法或其对的任何方法的实现。
在远程方法调用的参数和返回值中,不是远程对象的对象是按值传递的。因此,在接收方的 Java 虚拟机中创建对象的副本。接收方对对象状态的任何更改仅反映在接收方的副本中,而不是发送方的原始实例中。发送方对对象状态的任何更改仅反映在发送方的原始实例中,而不是接收方的副本中。
实现中最复杂的方法是 方法。 方法用于启动 ,因此需要进行必要的初始化和管理工作,以准备服务器接受来自客户端的调用。这个方法不是一个远程方法,这意味着它不能从不同的 Java 虚拟机中调用。由于 方法声明为 ,该方法根本不与对象关联,而是与类 关联。
方法的第一个任务是创建和安装安全管理器,以保护来自 Java 虚拟机内运行的不受信任的下载代码对系统资源的访问。安全管理器确定下载的代码是否可以访问本地文件系统或执行任何其他特权操作。
如果一个 RMI 程序没有安装安全管理器,RMI 将不会为作为参数接收的对象或远程方法调用的返回值下载类(除了从本地类路径)。这个限制确保下载代码执行的操作受安全策略约束。
这是创建和安装安全管理器的代码:
接下来, 方法创建了一个 实例,并使用以下语句将其导出到 RMI 运行时:
静态的 方法导出提供的远程对象,以便它可以接收来自远程客户端的远程方法调用。第二个参数是一个 ,指定用于监听对象的传入远程调用请求的 TCP 端口。通常使用值零,指定使用匿名端口。实际端口将由 RMI 或底层操作系统在运行时选择。但也可以使用非零值指定用于监听的特定端口。一旦 调用成功返回, 远程对象就准备好处理传入的远程调用。
方法返回导出的远程对象的存根。请注意,变量 的类型必须是 ,而不是 ,因为远程对象的存根只实现导出的远程对象实现的远程接口。
方法声明可以抛出 ,这是一个已检查的异常类型。 方法使用其 / 块处理此异常。如果不以这种方式处理异常,则必须在 方法的 子句中声明 。如果请求的端口已绑定到其他用途,尝试导出远程对象可能会抛出 ,例如,如果必要的通信资源不可用。
在客户端可以调用远程对象的方法之前,必须首先获取对远程对象的引用。获取引用可以通过与程序中获取任何其他对象引用的方式相同完成,例如通过将引用作为方法的返回值的一部分或作为包含这样一个引用的数据结构的一部分。
系统提供了一种特定类型的远程对象,即 RMI 注册表,用于查找其他远程对象的引用。RMI 注册表是一个简单的远程对象命名服务,使客户端能够通过名称获取对远程对象的引用。注册表通常仅用于定位 RMI 客户端需要使用的第一个远程对象。然后,该第一个远程对象可能提供支持以查找其他对象。
远程接口是在注册表中绑定(或注册)和查找远程对象的 API。类提供了用于在特定网络地址(主机和端口)合成远程引用到注册表的静态方法。这些方法创建包含指定网络地址的远程引用对象,而不执行任何远程通信。还提供了用于在当前 Java 虚拟机中创建新注册表的静态方法,尽管此示例未使用这些方法。一旦远程对象在本地主机上的 RMI 注册表中注册,任何主机上的客户端都可以按名称查找远程对象,获取其引用,然后调用对象上的远程方法。注册表可以被所有运行在主机上的服务器共享,或者单个服务器进程可以创建和使用自己的注册表。
类使用以下语句为对象创建名称:
代码然后将名称添加到运行在服务器上的 RMI 注册表中。此步骤稍后通过以下语句完成:
此调用会对本地主机上的 RMI 注册表进行远程调用。与任何远程调用一样,此调用可能导致抛出,该异常由方法末尾的块处理。
注意调用的以下内容:
- 的无参数重载在本地主机上和默认注册表端口 1099 上合成对注册表的引用。如果注册表在除 1099 之外的端口上创建,则必须使用具有参数的重载。
- 当对注册表进行远程调用时,传递的是远程对象的存根而不是远程对象本身的副本。远程实现对象,例如的实例,永远不会离开它们被创建的 Java 虚拟机。因此,当客户端在服务器的远程对象注册表中执行查找时,会返回存根的副本。在这种情况下,远程对象实际上是通过(远程)引用而不是通过值传递的。
- 出于安全原因,应用程序只能在运行在同一主机上的注册表上、或远程对象引用。这种限制防止远程客户端删除或覆盖服务器注册表中的任何条目。然而,可以从任何主机(本地或远程)请求。
一旦服务器向本地 RMI 注册表注册,它会打印一条消息,指示它已准备好开始处理调用。然后,方法完成。不需要有一个线程等待来保持服务器处于活动状态。只要在另一个 Java 虚拟机中有对对象的引用,无论是本地还是远程,对象都不会被关闭或垃圾回收。因为程序在注册表中绑定了对的引用,所以它可以从远程客户端,即注册表本身,访问。RMI 系统保持的进程运行。可用于接受调用,并且在其绑定从注册表中移除且没有远程客户端持有对对象的远程引用时才会被回收。
在方法中的最后一段代码处理可能出现的任何异常。代码中可能抛出的唯一已检查异常类型是,可能是由调用或注册表调用引起的。在任何情况下,程序在打印错误消息后不能做更多事情,只能退出。在一些分布式应用中,可以从远程调用失败中恢复。例如,应用程序可以尝试重试操作或选择另一个服务器继续操作。
原文:
计算引擎是一个相对简单的程序:它运行交给它的任务。计算引擎的客户端更加复杂。客户端需要调用计算引擎,但也必须定义计算引擎执行的任务。
在我们的示例中,客户端由两个单独的类组成。第一个类查找并调用对象。第二个类实现接口并定义计算引擎执行的工作。类的工作是计算到某个小数位数的的值。
非远程接口定义如下:
调用对象方法的代码必须获取对该对象的引用,创建一个对象,然后请求执行该任务。稍后将显示任务类的定义。使用单个参数构造对象,该参数是所需结果的精度。任务执行的结果是表示计算到指定精度的的。
这里是的源代码,主要客户端类:
像服务器一样,客户端首先安装安全管理器。这一步是必要的,因为接收服务器远程对象存根的过程可能需要从服务器下载类定义。为了让 RMI 下载类,必须启用安全管理器。
安装安全管理器后,客户端构造一个名称用于查找远程对象,使用与绑定其远程对象相同的名称。此外,客户端使用 API 合成服务器主机上注册表的远程引用。第一个命令行参数的值是对象运行的远程主机的名称。然后客户端在注册表上调用方法,通过名称在服务器主机的注册表中查找远程对象。使用的重载版本具有单个参数,返回命名主机和默认注册表端口 1099 的注册表引用。如果注册表在除 1099 之外的端口上创建,则必须使用具有参数的重载。
接下来,客户端创建一个新的对象,将第二个命令行参数解析为整数传递给构造函数。这个参数指示计算中要使用的小数位数。最后,客户端调用远程对象的方法。传入调用的对象返回一个类型的对象,程序将其存储在变量中。最后,程序打印结果。下图描述了客户端、和之间消息流的过程。
类实现了接口,并计算了的值到指定的小数位数。对于这个示例,实际算法并不重要。重要的是算法是计算密集型的,这意味着你希望它在一个能力强大的服务器上执行。
这是的源代码,该类实现了接口:
注意,所有可序列化的类,无论它们是否直接或间接实现了接口,都必须声明一个名为的 字段,以确保在不同版本之间的序列化兼容性。如果该类之前没有发布过版本,则该字段的值可以是任何值,类似于使用的,只要该值在未来版本中一致使用即可。如果该类的先前版本已发布但没有显式声明,但与该版本的序列化兼容性很重要,则必须使用先前版本的默认隐式计算值作为新版本显式声明的值。可以运行工具来确定先前版本的默认计算值。
这个示例最有趣的特点是实现对象在对象作为参数传递给方法之前从不需要类的定义。在那时,RMI 会将该类的代码加载到对象的 Java 虚拟机中,调用方法,并执行任务的代码。结果,对于任务来说是一个对象,会被传回给调用客户端,在那里用于打印计算结果。
供给的对象计算值这一事实对于对象来说并不重要。你也可以实现一个任务,比如通过使用概率算法生成一个随机素数。这个任务也会需要大量计算,因此是传递给的一个很好的选择,但它需要非常不同的代码。当对象传递给对象时,这段代码也可以被下载。就像在需要时引入计算的算法一样,生成随机素数的代码也会在需要时被引入。对象只知道它接收到的每个对象都实现了方法。对象不知道,也不需要知道实现的具体内容。
原文:
现在,计算引擎示例的代码已经编写完成,需要进行编译和运行。
编译示例程序
在这一部分,您将学习如何编译组成计算引擎示例的服务器和客户端程序。
运行示例程序
最后,你运行服务器和客户端程序,从而计算出的值。
原文:
在一个真实的场景中,例如部署了像计算引擎这样的服务,开发人员可能会创建一个包含 和 接口的 Java 存档(JAR)文件,供服务器类实现和客户端程序使用。接下来,一个开发人员,也许是接口 JAR 文件的相同开发人员,会编写 接口的实现,并将该服务部署在客户端可用的机器上。客户端程序的开发人员可以使用 JAR 文件中包含的 和 接口,独立开发一个任务和客户端程序,使用 服务。
在本节中,您将学习如何设置 JAR 文件、服务器类和客户端类。您将看到客户端的 类将在运行时下载到服务器上。此外, 和 接口将在运行时从服务器下载到注册表中。
该示例将接口、远程对象实现和客户端代码分为三个包:
- – 和 接口
- – 实现类
- – 客户端代码和 任务实现
首先,您需要构建接口 JAR 文件,以提供给服务器和客户端开发人员。
首先,您需要编译 包中的接口源文件,然后构建一个包含它们类文件的 JAR 文件。假设用户 已经编写了这些接口,并将源文件放在 Windows 的目录 或 Solaris OS 或 Linux 的目录 中。给定这些路径,您可以使用以下命令编译接口并创建 JAR 文件:
微软 Windows:
Solaris OS 或 Linux:
命令由于 选项显示如下输出:
现在,您可以将 文件分发给服务器和客户端应用程序的开发人员,以便他们可以利用这些接口。
使用 编译器构建服务器端或客户端类后,如果其中任何类需要由其他 Java 虚拟机动态下载,您必须确保它们的类文件放在网络可访问的位置。在本例中,对于 Solaris OS 或 Linux,这个位置是 ,因为许多 Web 服务器允许通过构造为 的 HTTP URL 访问用户的 目录。如果您的 Web 服务器不支持这种约定,您可以在 Web 服务器的层次结构中使用不同的位置,或者您可以使用文件 URL。在 Solaris OS 或 Linux 上,文件 URL 的形式为 ,在 Windows 上的形式为 。您也可以根据需要选择另一种类型的 URL。
类文件的网络可访问性使得 RMI 运行时在需要时可以下载代码。RMI 不会为代码下载定义自己的协议,而是使用 Java 平台支持的 URL 协议(例如 HTTP)来下载代码。请注意,使用完整的重量级 Web 服务器来提供这些类文件是不必要的。例如,可以在 找到一个简单的 HTTP 服务器,提供了在 RMI 通过 HTTP 下载类所需的功能。
另请参阅 远程方法调用主页。
包仅包含一个服务器端实现类 ,这是远程接口 的实现。
假设开发 类的用户 已经将 放在 Windows 的目录 或 Solaris OS 或 Linux 的目录 中。她正在部署供客户下载的类文件在她的 目录的子目录中,Windows 上为 或 Solaris OS 或 Linux 上为 。这个位置可以通过一些 Web 服务器访问,如 。
类依赖于 和 接口,这些接口包含在 JAR 文件中。因此,在构建服务器类时,您需要将 文件放在类路径中。假设 文件位于 Windows 的目录 或 Solaris OS 或 Linux 的目录 中。有了这些路径,您可以使用以下命令构建服务器类:
Microsoft Windows:
Solaris OS 或 Linux:
的存根类实现了接口,该接口引用了接口。因此,这两个接口的类定义需要对其他 Java 虚拟机(如注册表的 Java 虚拟机)可访问,以便存根能够接收。客户端 Java 虚拟机将已经在其类路径中包含了这些接口,因此实际上不需要下载它们的定义。目录下的文件可以起到这个作用。
现在,计算引擎已经准备好部署。你现在可以这样做,或者等到构建客户端之后再部署。
包含两个类,,主要客户端程序,和,客户端对接口的实现。
假设开发客户端类的用户已经将和放置在 Windows 系统的目录下,或者 Solaris OS 或 Linux 系统的目录下。他正在将计算引擎的类文件部署在他的目录的子目录中,Windows 系统为,Solaris OS 或 Linux 系统为。这个位置可以通过一些 Web 服务器访问,如。
客户端类依赖于和接口,这些接口包含在 JAR 文件中。因此,在构建客户端类时,你需要将文件放在类路径中。假设文件位于 Windows 系统的目录下,或者 Solaris OS 或 Linux 系统的目录下。有了这些路径,你可以使用以下命令来构建客户端类:
Microsoft Windows:
Solaris OS 或 Linux:
只有类需要放置在目录中,因为只有类需要在计算引擎的 Java 虚拟机中可用以供下载。现在,你可以先运行服务器,然后再运行客户端。
原文:
服务器和客户端程序都安装了安全管理器。当您运行任一程序时,您需要指定一个安全策略文件,以便代码被授予其运行所需的安全权限。这是一个用于服务器程序的示例策略文件。
这是一个用于客户端程序的示例策略文件。
对于这两个示例策略文件,所有权限都授予程序本地类路径中的类,因为本地应用程序代码是受信任的,但不授予从其他位置下载的代码任何权限。因此,计算引擎服务器限制其执行的任务(其代码未知是否受信任且可能具有敌意)执行需要安全权限的任何操作。示例客户端的任务不需要任何权限来执行。
在此示例中,服务器程序的策略文件名为,客户端程序的策略文件名为。
在启动计算引擎之前,您需要启动 RMI 注册表。RMI 注册表是一个简单的服务器端引导命名工具,使远程客户端能够获取对初始远程对象的引用。它可以通过命令启动。在执行之前,您必须确保您将运行的 shell 或窗口要么没有设置环境变量,要么具有不包括您希望下载到远程对象的客户端的任何类路径的环境变量。
要在服务器上启动注册表,请执行命令。此命令不会产生任何输出,并且通常在后台运行。在此示例中,注册表在主机上启动。
Microsoft Windows(如果不可用,请使用):
Solaris 操作系统或 Linux:
默认情况下,注册表在端口 1099 上运行。要在不同端口上启动注册表,请在命令行上指定端口号。不要忘记取消设置环境变量。
Microsoft Windows:
Solaris 操作系统或 Linux:
一旦注册表启动,你可以启动服务器。你需要确保文件和远程对象实现类都在你的类路径中。当你启动计算引擎时,你需要使用属性指定服务器类的网络访问位置。在这个例子中,要提供下载的服务器端类是和接口,在用户的目录中的文件中可用。计算引擎服务器在主机上启动,与注册表启动的主机相同。
Microsoft Windows:
Solaris OS 或 Linux:
上述命令定义了以下系统属性:
- 属性指定了一个代码库 URL,从这个服务器可以下载源自*的类的定义。如果代码库指定了一个目录层次结构(而不是一个 JAR 文件),你必须在代码库 URL 的末尾包含一个斜杠。
- 属性指定了要放在此 Java 虚拟机中导出的远程对象存根中的主机名或地址。当客户端尝试通信远程方法调用时,客户端使用的值是主机名或地址。默认情况下,RMI 实现使用服务器的 IP 地址,如 API 所示。然而,有时,这个地址对于所有客户端都不合适,一个完全合格的主机名会更有效。为了确保 RMI 使用一个对所有潜在客户端都可路由的主机名(或 IP 地址)作为服务器,设置属性。
- 属性用于指定包含您打算授予的权限的策略文件。
一旦注册表和计算引擎运行起来,你可以启动客户端,指定以下内容:
- 客户端提供其类(类)的位置,使用属性
- 属性用于指定包含您打算授予各种代码片段的权限的安全策略文件
- 作为命令行参数,服务器的主机名(以便客户端知道在哪里找到远程对象)和在
计算中使用的小数位数
在另一台主机上启动客户端(例如名为的主机)如下:
Microsoft Windows:
Solaris OS 或 Linux:
注意,类路径是在命令行上设置的,以便解释器可以找到客户端类和包含接口的 JAR 文件。还要注意,属性的值,指定一个目录层次结构,以斜杠结尾。
在启动客户端后,将显示以下输出:
以下图示说明了在程序执行期间、服务器和客户端获取类的位置。
当服务器在注册表中绑定其远程对象引用时,注册表会下载存根类依赖的和接口。这些类是从服务器的 Web 服务器或文件系统下载的,具体取决于启动服务器时使用的代码库 URL 的类型。
因为客户端在其类路径中同时具有和接口的定义,它从其类路径加载它们的定义,而不是从服务器的代码库加载。
最后,当对象在远程调用中传递给对象时,类被加载到服务器的 Java 虚拟机中。类是由服务器从客户端的 Web 服务器或文件系统加载的,具体取决于启动客户端时使用的代码库 URL 的类型。
原文:
在本教程中,您将了解内置的 Java™安全功能如何保护您免受恶意程序的侵害。您将看到如何使用工具来控制对资源的访问,生成和检查数字签名,以及创建和管理用于签名生成和检查所需的密钥。您还将看到如何将加密服务(如数字签名生成和检查)整合到您的程序中。
Java 开发工具包(JDK™)提供的安全功能面向各种受众:
- 运行程序的用户:
内置的安全功能可保护您免受恶意程序(包括病毒)的侵害,保护您文件的隐私和关于您的信息,并验证每个代码提供者的身份。当您需要时,您可以对应用程序和小程序进行安全控制。
- 开发人员:
您可以使用 API 方法将安全功能整合到您的程序中,包括加密服务和安全检查。API 框架使您能够定义和整合自己的权限(控制对特定资源的访问)、加密服务实现、安全管理器实现和策略实现。此外,还提供了用于管理您信任的人的公钥/私钥对和公钥证书的类。
- 系统管理员、开发人员和用户:
JDK 工具管理您的密钥库(密钥和证书的数据库);为 JAR 文件生成数字签名,并验证这些签名的真实性和已签名内容的完整性;以及创建和修改定义安装安全策略的策略文件。
注意: 对于想要创建小程序和 Java Web 启动应用程序的开发人员,请参阅 Java 小程序以获取安全信息。
创建策略文件 展示了如何通过策略文件控制资源访问。有关策略配置文件的最新信息,请参阅策略指南 页面。
快速浏览控制应用程序 在前一课程的基础上展示了资源访问的控制,例如对于在安全管理器下运行的应用程序,除非在策略文件中明确允许,否则不允许读取或写入文件等资源访问。
用于安全代码和文件交换的 API 和工具使用定义了数字签名、证书和密钥库,并讨论了它们为何需要。它还回顾了适用于接下来三个课程的信息,这些课程通常需要使用工具或 API 生成签名、导出/导入证书等步骤。
签署代码并授予权限展示了所有与安全相关的工具的使用。它展示了开发人员签署和分发代码供他人运行的步骤。本课程还展示了运行代码的人(或系统管理员)如何在策略文件中添加条目以授予代码所需的资源访问权限。
文件交换展示了一个人使用工具签署重要文件,如合同,并导出与用于签署合同的私钥对应的公钥证书。然后本课程展示了另一个人如何导入证书并验证签名,该人收到了合同、签名和公钥证书。
生成和验证签名逐步引导您通过一个示例,使用 JDK 安全 API 编写 Java 程序生成密钥,使用私钥为数据生成数字签名,并将公钥和签名导出到文件。然后示例展示了编写第二个程序,该程序可能预期在另一个人的计算机上运行,导入公钥并验证签名的真实性。最后,示例讨论了基本程序使用的方法的潜在弱点,并演示了可能的替代方法和提供和导入密钥的方法,包括在证书中。
实现自己的权限演示了如何编写一个定义自己特殊权限的类。
JDK 安全发布文档可以在安全指南页面找到。此索引页面列出了规范,提供了关于最新安全功能的详细信息,包括架构规范、使用指南、API 文档和工具文档。
原文:
安全功能帮助您保护程序和数据免受伤害,保持数据受到保护和私密,并在安全意识的运行时环境中部署新应用程序。
Java 还提供了几个工具,帮助您管理对系统资源的访问;创建、存储和维护加密的公共和私有密码(密钥对)和证书;以及在部署过程中创建和签名 jar 文件。
注意: 要了解 Java SE 7 中支持的安全功能的简要概述,请参阅安全指南目录中的安全概述白皮书。
原文:
这节课展示了如何创建一个控制资源访问的策略文件。
本课程的步骤是:
- 设置策略文件以授予所需权限
原文:
策略文件是一个 ASCII 文本文件,可以通过文本编辑器或本节中演示的图形化策略工具来编写。策略工具可以节省您的输入时间,消除您需要了解策略文件所需语法的需求,从而减少错误。
本课程使用策略工具创建名为 的策略文件,在其中您将添加一个 策略条目,授予来自 目录的代码写入权限。
按照以下步骤创建和修改您的新策略文件:
- 启动策略工具
- 授予所需权限
- 保存策略文件
UNIX 用户注意事项: 这些步骤说明了如何为 Windows 系统创建策略文件。如果您在 UNIX 系统上工作,步骤完全相同。当文本中说要将策略文件存储在 目录中时,您可以将其存储在其他目录中。本课程中的示例假定您将其存储在 目录中。
原文:
要启动 Policy Tool,只需在命令行中输入以下内容:
这将打开 Policy Tool 窗口。
每次启动 Policy Tool 时,它会尝试从用户策略文件中填充此窗口中的策略信息。用户策略文件默认在您的主目录中命名为。如果 Policy Tool 找不到用户策略文件,它会发出警告并显示一个空白的 Policy Tool 窗口(一个带有标题和按钮但没有数据的窗口),如下图所示。
然后,您可以选择打开现有的策略文件或创建新的策略文件。
第一次运行 Policy Tool 时,您会看到空白的 Policy Tool 窗口,因为用户策略文件尚不存在。您可以立即继续创建新的策略文件,如下一步所述。
原文:
要创建新条目,请在主策略工具窗口中单击 添加策略条目 按钮。这将显示如下图所示的策略条目对话框。
策略条目指定了来自特定代码源的一个或多个权限–来自特定位置(URL)的代码,由特定实体签名的代码,或两者兼有。
CodeBase 和 SignedBy 文本框指定您要授予权限的代码,这些权限将添加到文件中。
- CodeBase 值表示代码源位置;您授予来自该位置的代码的权限。空的 CodeBase 条目表示“任何代码”–代码的来源并不重要。
- SignedBy 值表示存储在密钥库中的证书的别名。该证书内的公钥用于验证代码上的数字签名。您授予由与别名指定的密钥库条目中的公钥对应的私钥签名的代码的权限。SignedBy 条目是可选的;省略它表示“任何签名者”–代码是否签名或由谁签名并不重要。
如果您同时拥有 CodeBase 和 SignedBy 条目,权限仅授予来自指定位置且由指定别名签名的代码。
您可以授予存储示例的位置(URL)的所有代码权限。
在策略条目对话框的 CodeBase 文本框中键入以下 URL:
注意: 这是一个 URL。因此,它必须始终使用斜杠作为分隔符,而不是反斜杠。
将 SignedBy 文本框留空,因为您不需要代码签名。
注意: 要授予权限给任何代码( 文件),不仅仅是从先前指定的目录,而是从 目录及其子目录中,将以下 URL 键入 CodeBase 框中:
您已经指定了代码的来源(CodeBase),并且代码不需要签名(因为没有 SignedBy 值)。
您现在已经指定了此策略条目,因此在策略条目对话框中单击 完成 按钮。策略工具窗口现在包含代表策略条目的一行,显示 值。
注意: 我们将在下一课中授予此新策略条目的权限。
原文:
要保存您正在创建的新策略文件,请从文件菜单中选择另存为命令。这将显示另存为对话框。
在控制应用程序快速入门课程中的示例假设您将策略文件存储在驱动器上的目录中。
导航到目录。键入文件名,然后点击保存。
策略文件现在已保存,其名称和路径显示在标记为的文本框中。
通过从文件菜单中选择退出来退出策略工具。
原文:
先决条件课程: 创建策略文件
本课程展示如何使用安全管理器为应用程序授予或拒绝对系统资源的访问权限。本课程还展示了资源访问,如读取或写入文件,对于使用安全管理器运行的应用程序,除非在策略文件中明确允许,否则是不允许的。
本课程的步骤为:
- 观察应用程序自由
- 查看如何限制应用程序
- 设置策略文件以授予所需权限
- 查看策略文件的效果
原文:
当应用程序运行时,不会自动安装安全管理器。在下一步中,您将看到如何将相同的安全策略应用于在本地文件系统上找到的应用程序和下载的沙箱小程序。但首先,让我们证明默认情况下未安装安全管理器用于应用程序,因此应用程序可以完全访问资源。
在您的计算机上创建一个名为的文件,可以通过复制或下载源代码来实现。
本课程中的示例假定您将放在目录中(如果您使用 Windows 系统)或在 UNIX 上的目录中。
如您所见,如果检查源文件,此程序尝试获取(读取)属性值,其名称为,,和。
现在编译并运行。您应该看到类似以下的输出:
这表明应用程序被允许访问所有属性值,如下图所示。
原文:
正如您在上一步骤中看到的,当 Java 运行时运行一个应用程序时,它不会自动安装安全管理器。要将相同的安全策略应用于本地文件系统中找到的应用程序和下载的沙箱小程序,您可以使用新的命令行参数调用解释器。
要使用默认安全管理器执行应用程序,请键入以下内容:
以下是程序的输出:
过程如下图所示。
Java 运行时默认加载默认策略文件,并授予所有代码访问一些常用属性(如和)的权限。这些属性不是安全敏感的,因此授予这些权限通常不会构成安全风险。
尝试访问的其他属性和不在系统策略文件授予读取权限的属性之列。因此,一旦尝试访问这些属性中的第一个()时,安全管理器会阻止访问并报告。此异常表示当前生效的策略,其中包含一个或多个策略文件中的条目,不允许读取属性的权限。
注意: 代码始终可以从与其所在目录相同的目录(或该目录的子目录)中读取文件;它不需要明确的权限来这样做。代码还可以获取其执行目录的路径名,而此路径名可能包含敏感信息。例如,如果代码是从主目录(或主目录的子目录)执行的,则路径名可能会显示当前用户的名称。
默认策略文件, 默认位于:
- Windows:
- UNIX:
请注意,java.home代表属性的值,该属性是指定 JRE 安装目录的系统属性。因此,如果 JRE 安装在 Windows 上名为,在 UNIX 上名为的目录中,则系统策略文件位于:
- Windows:
- UNIX:
原文:
这一步使用策略工具实用程序打开名为的策略文件,该文件是在创建策略文件课程中创建的。您将添加一个新的策略条目,允许来自存储的目录的代码读取和属性值,如下图所示。
)
步骤如下。
- 打开策略文件
- 授予所需的权限
- 保存策略文件
UNIX 用户注意: 本说明演示了为 Windows 系统创建策略文件。如果您在 UNIX 系统上工作,则步骤完全相同,只有以下区别。
- 您从您的主目录中的目录中检索文件。
- 对于授予所需权限的步骤中的CodeBase URL,您可以将替换为。或者,您可以直接指定您的主目录,而不是引用属性,如。
原文:
通过在命令行中键入以下内容启动策略工具:
这将打开策略工具窗口。要打开策略文件,请在文件菜单中使用打开命令。这将显示一个打开对话框,您可以使用它来浏览目录结构,直到找到包含策略文件的目录(即目录)。
选择该目录中的文件,然后选择打开按钮。
这将从策略文件中填充策略工具窗口中的信息,包括策略文件名和由创建策略文件课程创建的CodeBase部分的策略条目。
原文:
要授予应用程序读取和属性值的权限,必须创建一个授予这些权限的策略条目。在主策略工具窗口中选择添加策略条目按钮。这将弹出策略条目对话框,如下图所示。
在CodeBase文本框中键入以下文件 URL,以指示您将授予来自指定目录中的代码的权限,该目录是存储的目录。
(注意,这是一个 URL,因此必须始终使用斜杠,而不是反斜杠。)
将SignedBy文本框留空,因为您不需要代码签名。
要添加读取属性值的权限,请选择添加权限按钮。这将弹出权限对话框。
执行以下操作。
- 从权限下拉列表中选择属性权限。完整的权限类型名称()现在出现在下拉列表右侧的文本框中。
- 在标有目标名称列表右侧的文本框中键入以下内容,以指定属性:
- 通过从操作下拉列表中选择读取选项来指定读取此属性的权限。
现在权限对话框如下所示。
选择确定按钮。新权限将出现在策略条目窗口中的一行中。
要添加读取属性值的权限,请再次选择添加权限按钮。在权限对话框中,执行以下操作:
- 从权限下拉列表中选择属性权限。
- 在标有目标名称列表右侧的文本框中键入以下内容,以指定属性:
- 通过从操作下拉列表中选择读取选项来指定读取此属性的权限。
现在权限对话框如下所示。
选择确定按钮。新权限和先前添加的权限将出现在策略条目窗口中的行中,如下图所示。
您现在已经完成了指定此策略条目的操作,因此在策略条目对话框中选择完成按钮。策略工具窗口现在包括表示新策略条目的一行,显示CodeBase值。
原文:
要保存策略文件,只需在文件菜单中选择保存命令。
然后从文件菜单中选择退出命令退出策略工具。
原文:
现在您已经向策略文件添加了所需的策略条目,当您使用安全管理器执行应用程序时,您应该能够读取指定的属性,如下图所示。
每当您运行一个小程序,或者一个带有安全管理器的应用程序时,默认加载和使用的策略文件是位于以下目录之一的“安全属性文件”中指定的文件。
- Windows:
- UNIX:
注意: 环境变量指定了 JRE 安装的目录。
策略文件的位置是指定为属性值的形式为:
其中变量表示一个数字。请在以下形式的行中指定每个属性值:
其中URL是 URL 规范。例如,默认的策略文件,有时分别称为系统和用户策略文件,在安全属性文件中定义为
注意: 在安全属性文件中使用符号是指定属性值的一种方式。因此将在运行时被实际的属性值替换,该属性值指示了 JRE 安装的目录,将被属性的值替换,例如,。
有两种可能的方式可以使文件被视为整体策略的一部分,除了在安全属性文件中指定的策略文件。您可以通过将附加策略文件指定为传递给运行时系统的属性,如方法 1 中所述,或者在安全属性文件中添加指定附加策略文件的行,如方法 2 中所讨论的那样。
您可以使用解释器命令行参数来指定一个应该在安全属性文件中指定的策略文件之外使用的策略文件。
确保您在包含和的目录中。然后,您可以运行应用程序,并通过在一行上键入以下命令将策略文件传递给解释器:
注意: 请记住,为了使用安全管理器运行应用程序,需要,如查看如何限制应用程序步骤中所示。
该程序报告了和属性的值。
如果应用程序仍然报告错误,则策略文件中存在问题。使用策略工具检查您在设置策略文件以授予所需权限步骤中创建的策略条目。
您可以在安全属性文件中指定多个 URL,所有指定的策略文件都将被加载。因此,让解释器考虑您的文件的策略条目的一种方法是在安全属性文件中添加指定该策略文件的条目。
重要提示: 如果您正在运行自己的 JDK 副本,您可以轻松编辑安全属性文件。如果您正在运行与其他用户共享的版本,只有在具有写入权限或在适当时向系统管理员请求修改文件时,您才能修改系统范围的安全属性文件。但是,对于本教程测试,您可能不应该对系统范围的策略文件进行修改。我们建议您只需阅读以下内容,看看如何操作,或者安装您自己的私人版本的 JDK 用于教程课程。
要修改安全属性文件,请在适合编辑 ASCII 文本文件的编辑器中打开它。然后在包含的行之后添加以下行:如果您在 Windows 系统上,请添加
如果您在 UNIX 系统上,请添加
在 UNIX 系统上,您还可以显式指定您的主目录,如下所示
现在,您应该能够成功运行以下内容。
与方法 1 一样,如果仍然出现安全异常,则策略文件中存在问题。使用策略工具检查您在设置策略文件以授予所需权限步骤中创建的策略条目。然后修复任何拼写错误或其他错误。
重要提示: 除非您正在运行本教程课程,否则无需包含文件。要排除此文件,请打开安全属性文件并删除刚刚添加的行。
在继续之前,您可能希望删除您刚刚在安全属性文件中添加的行(或将其注释掉),因为您可能不希望在不运行教程课程时包含文件。
原文:
本课程解释了为什么需要数字签名、证书和密钥库。该课程还比较了使用这些工具与 JDK 安全 API 生成签名的情况。这些工具的使用在接下来的两节课中进行演示,签署代码并授予权限 和 文件交换。API 的使用在 生成和验证签名 课程中进行演示。
本课程包含以下部分
- 代码和文档安全
- 工具和 API 注释
- 使用 JDK 安全 API 签署文档
- 使用工具签署代码或文档
如果您通过电子方式向某人发送重要文件(或文件)、或要运行的小程序或应用程序,接收方需要一种方法来验证文件或代码是否来自您,并且在传输过程中未被修改(例如,被恶意用户拦截)。数字签名、证书和密钥库都有助于确保您发送的文件的安全性。
数字签名
使用数字签名的基本思想如下。
- 您使用您可以通过或安全 API 方法生成的私钥对文档或代码进行“签名”。也就是说,您使用工具或安全 API 方法为文档或代码生成数字签名。
- 您将签名的文档发送给接收方。
- 您还向接收方提供您的公钥。这个公钥对应于您最初用于生成签名的私钥。
- 接收方使用您的公钥来验证您的文件是否来自您,并且在到达之前未被修改。
接收方需要确保您的公钥本身是真实的,然后才能使用它来验证您的签名是否真实。因此,您通常会提供一个包含您的公钥以及可以为您的密钥真实性作证的证书颁发机构的密钥的证书。有关详细信息,请参见下一节。
有关签名和验证术语和概念的更多信息,以及有关好处的进一步解释,请参见“JAR 文件打包程序”课程的 签署 JAR 文件 部分。
证书
证书包含:
- 一个公钥。
- 证书的“显著名称”信息是指证书的实体(个人、公司等)的信息。这个实体被称为证书主体或所有者。显著名称信息包括以下属性(或其子集):实体的名称、组织单位、组织、城市或地点、州或省和国家代码。
- 数字签名。证书由一个实体,颁发者,签名,以证明封闭的公钥是另一个实体,所有者的实际公钥。
- 签名者(颁发者)的显著名称信息。
收件人检查证书是否有效的一种方法是使用颁发者(签名者)的公钥验证其数字签名。该密钥本身可以存储在另一个证书中,该证书的签名也可以通过使用下一个证书的颁发者的公钥进行验证,而该密钥可能也存储在另一个证书中,依此类推。当你到达一个你已经信任的公钥并用它来验证相应证书上的签名时,你可以停止检查。
如果收件人无法建立信任链,那么他/她可以使用 的 或 命令计算证书的指纹。指纹是一个相对较短的数字,可以唯一且可靠地识别证书。(从技术上讲,指纹是证书信息的哈希值,使用消息摘要函数。)然后,收件人可以打电话给证书所有者,并将收到的证书的指纹值与发送的证书进行比较。如果指纹相同,则证书相同。
因此,你可以确保证书在传输过程中没有被修改。在处理证书时的另一个潜在不确定性是发送者的身份。有时证书是自签名的,即使用与证书中的公钥对应的私钥签名;颁发者与主体相同。
自签名证书对于开发和测试应用程序很有用。然而,在部署给用户之前,从一个受信任的第三方(称为认证机构(CA))那里获取证书是必要的。为此,你向 CA 发送一个自签名证书签名请求(CSR)。CA 验证 CSR 上的签名和你的身份,可能通过检查你的驾驶执照或其他信息。然后,CA 通过使用自己的(CA 的)私钥签发证书并为你作为公钥所有者背书。任何信任颁发 CA 的公钥的人现在都可以验证证书上的签名。在许多情况下,颁发 CA 本身可能有一个来自 CA 层次结构更高层的证书,导致证书链。
你信任的实体的证书通常被导入到你的密钥库中作为“受信任的证书”。每个这样的证书中的公钥可以用来验证使用相应私钥生成的签名。这样的验证可以通过以下方式完成:
- 工具(如果文档/代码和签名出现在一个 JAR 文件中),
- API 方法,或
- 运行时系统,在尝试访问资源时,如果策略文件指定允许代码尝试访问的资源访问,且其签名是真实的,则允许访问。代码的类文件和签名必须在一个 JAR 文件中。
如果您要向他人发送签名的代码或文档,则需要向他们提供包含与用于签署代码/文档的私钥对应的公钥的证书。 的 命令或 API 方法可以将您的证书从密钥库导出到文件中,然后可以将该文件发送给需要的任何人。接收证书的人可以将其导入到密钥库中作为受信任的证书,例如使用 API 方法或 的 命令。
如果您使用 工具为 JAR 文件生成签名,则该工具会从您的密钥库中检索您的证书及其支持的证书链。然后,该工具将它们与签名一起存储在 JAR 文件中。
密钥库
私钥及其相关的公钥证书存储在受密码保护的数据库中,称为密钥库。密钥库可以包含两种类型的条目:上述讨论的受信任证书条目,以及密钥/证书条目,每个条目包含一个私钥和相应的公钥证书。密钥库中的每个条目都由一个别名标识。
密钥库所有者可以在密钥库中拥有多个密钥,通过不同的别名访问。别名通常以密钥库所有者在其中使用相关密钥的特定角色命名。别名也可以标识密钥的用途。例如,别名 可能用于标识一个用于签署个人电子邮件的密钥库条目,而别名 可能用于标识一个用于签署 JAR 文件的条目。
工具可用于
- 创建私钥及其相关的公钥证书
- 发出证书请求,然后将其发送给适当的认证机构
- 导入从您联系的认证机构获得的证书回复
- 导入属于其他方的公钥证书作为受信任的证书
- 管理您的密钥库
API 方法也可用于访问和修改密钥库。
请注意以下与数字签名相关的工具和 API 使用。
- 您可以使用 JDK 安全 API、工具或组合来生成密钥和签名,并导入证书。您可以使用这些 API 或工具功能与他人安全地交换文档。
- 要使用工具进行文档交换,文档必须放在 JAR(Java ARchive)文件中,可以通过工具创建。JAR 文件是将多个文件封装在一个位置的好方法。当文件被“签名”时,生成的数字签名字节需要存储在某个地方。当 JAR 文件被签名时,签名可以放在 JAR 文件本身中。这就是当您使用工具对 JAR 文件进行签名时发生的情况。
- 如果您正在创建将要签署的小程序代码,它需要放在 JAR 文件中。如果您正在创建可能受到安全管理器限制的应用程序代码,同样需要放在 JAR 文件中。您需要 JAR 文件的原因是,当策略文件指定由特定实体签名的代码允许一个或多个操作,例如特定文件读取或写入时,预期代码来自已签名的 JAR 文件。(术语“已签名代码”是指“出现在已签名 JAR 文件中的类文件中的代码”的简称。)
- 为了使运行时系统检查代码签名,将运行代码的人/组织首先需要将验证用于签署代码的私钥对应的公钥的证书导入其密钥库中。
- 为了使工具验证 JAR 文件签名的真实性,首先需要将接收到的 JAR 文件的人/组织导入其密钥库中,以验证与用于签署代码的私钥对应的公钥的证书。
- 目前还没有用于证书创建的 API。
生成和验证签名展示了如何使用 JDK 安全 API 签署文档。该课程展示了由拥有原始文档的人执行的一个程序会做什么
- 生成密钥,
- 使用私钥为数据生成数字签名,然后
- 导出公钥和签名到文件。
然后展示了另一个程序的示例,由数据、签名和公钥的接收者执行。展示了该程序如何
- 导入公钥
- 验证签名的真实性。
本课程还展示了导入和提供密钥的替代方法,包括证书。
签署代码并授予权限课程展示了如何使用 Java 安全工具将您的代码放入 JAR 文件中,对其进行签名,并导出您的公钥。然后展示了您的接收方如何使用相同的 Java 工具导入您的公钥证书,然后向策略文件添加条目,以授予您的代码访问受接收方控制的系统资源所需的权限。
文件交换课程教你如何使用 Java 安全工具签署文档,然后使用导出公钥证书,对应于使用签署该文档的私钥。然后它展示了如何接收者可以通过安装您的公钥证书并使用工具验证您的签名。
这两个课程有很多共同之处。在两种情况下,发送代码或文档的前两个步骤是:
- 使用工具创建包含文档或类文件的 JAR 文件。
- 生成密钥(如果尚不存在),使用的命令。
接下来的两个步骤是可选的:
- 使用的命令;然后将生成的证书签名请求发送给认证机构(CA),如 VeriSign。
- 使用的命令导入 CA 的响应。
接下来的两个步骤是必需的:
- 使用之前生成的私钥,使用工具对 JAR 文件进行签名。
- 使用的命令导出公钥证书。然后将签名的 JAR 文件和证书提供给接收者。
在两种情况下,签署的 JAR 文件和证书的接收者应该使用的命令将证书导入为受信任的证书。将尝试从要导入的证书到密钥库中已受信任的证书构建信任链。如果失败,将显示证书指纹并提示您进行验证。
如果发送的是代码,则接收者还需要修改策略文件以允许由导入证书中的公钥对应的私钥签名的代码访问所需资源。可以使用策略工具来执行此操作。
如果发送的是一个或多个文档,则接收者需要使用工具验证 JAR 文件签名的真实性。
本课程讨论了两个可选步骤。其他步骤在接下来的两个课程中涵盖,签署代码并授予权限和文件交换。
为公钥证书生成证书签名请求(CSR)
当使用生成公私钥对时,它会创建一个包含私钥和公钥的自签名证书的密钥库条目。(即,证书使用相应的私钥进行签名。)这在开发和测试应用程序时是足够的。
然而,如果证书由认证机构(CA)签名,其他人更有可能信任该证书。要获得由 CA 签名的证书,首先需要生成证书签名请求(CSR),通过类似以下命令:
这里alias用于访问包含私钥和公钥证书的密钥库条目,csrFile指定此命令创建的 CSR 使用的名称。
然后,你将此文件提交给 CA,如 VeriSign, Inc.。CA 对你(请求者/“主体”)进行验证,然后签署并返回一个验证你的公钥的证书。通过签署证书,CA 保证你是公钥的所有者。
在某些情况下,CA 会返回一系列证书,每个证书都用于验证链中前一个证书签发者的公钥。
导入来自 CA 的响应
在向认证机构(CA)提交证书签名请求(CSR)后,你需要通过导入 CA 返回给你的证书(或证书链)来用证书链替换密钥库中的原始自签名证书。
但首先,你需要在你的密钥库中(或下面描述的密钥库文件中)有一个"受信任证书"条目,用于验证CA的公钥。有了这样的条目,可以验证 CA 对证书的签名。也就是说,可以验证 CA 对证书的签名,或者验证 CA 发送给你作为 CSR 响应中的最终证书链上的最终证书的签名。
从 CA 导入证书作为"受信任证书"
在导入来自 CA 的证书回复之前,你需要在你的密钥库或文件中拥有一个或多个"受信任证书"。
- 如果证书回复是一个证书链,你只需要链中的顶层证书 – “根” CA 证书,用于验证该 CA 的公钥。
- 如果证书回复是单个证书,你需要签发它的 CA 的证书。如果该证书不是自签名的,你需要其签发者的证书,依此类推,直到自签名的"根" CA 证书。
文件代表一个系统范围的带有 CA 证书的密钥库。该文件位于 JRE 安全属性目录中,其中java.home是 JRE 安装目录。
重要提示:验证你的文件
由于你信任文件中的 CA 作为签署和颁发证书给其他实体的实体,你必须仔细管理文件。文件应只包含你信任的 CA 的证书。你有责任验证文件中捆绑的受信任根 CA 证书,并做出自己的信任决定。要从文件中删除一个不受信任的 CA 证书,使用命令的删除选项。你可以在 JRE 安装目录中找到文件。如果没有权限编辑此文件,请联系系统管理员。
文件包含许多受信任的 CA 证书。如果您将您的 CSR 发送给了这些受信任的供应商之一(比如 VeriSign),您就不需要将供应商的根证书作为受信任证书导入到您的密钥库中;您可以继续到下一个部分,查看如何从 CA 导入证书回复。
从 CA 获得的证书通常是自签名的或者由另一个 CA 签名的,此时您还需要一个证书来验证该 CA 的公钥。假设 ABC 公司是一个 CA,并且您获得了一个名为的文件,据称是来自 ABC 公司的自签名证书,用于验证该 CA 的公钥。
在将证书导入为“受信任”证书之前,请务必确保证书是有效的!首先查看它(使用的命令或者的命令,不带选项),并确保显示的证书指纹与预期的一致。您可以联系发送证书的人,并将您看到的指纹与他们展示的或者安全的公钥存储库展示的指纹进行比较。只有当指纹相等时,才能保证证书在传输过程中没有被替换为其他人(例如,攻击者)的证书。如果发生这样的攻击,并且您在导入证书之前没有检查证书,那么您将信任攻击者签署的任何内容。
如果您相信该证书是有效的,您可以通过类似以下命令将其添加到您的密钥库中:
此命令在密钥库中创建一个名为storefile指定的“受信任证书”条目。该条目包含来自文件的数据,并分配指定的别名。
从 CA 导入证书回复
一旦您已经导入了所需的受信任证书,就像前一节中描述的那样,或者它们已经存在于您的密钥库中或者在文件中,您可以导入证书回复,从而用证书链替换您的自签名证书。这个链将是 CA 对您的请求的回复中返回的(如果 CA 的回复是一个链)或者通过使用证书回复和已经在密钥库中或者密钥库文件中可用的受信任证书构建的(如果 CA 的回复是一个单一证书)。
举例来说,假设您将您的证书签名请求发送给了 VeriSign。然后您可以通过以下方式导入回复,假设返回的证书在certReplyFile指定的文件中:
在一行上输入此命令。
证书回复通过使用密钥库中的受信任证书进行验证,并可选择使用密钥库文件中配置的证书进行验证(如果指定了选项)。每个链中的证书都会被验证,使用链中下一级别的证书。您只需要信任链中顶级的“根”CA 证书。如果您尚未信任顶级证书,将显示该证书的指纹,并询问您是否要信任它。
指定(通过别名)条目的新证书链将替换与该条目关联的旧证书(或链)。只有在提供有效的keypass,用于保护条目私钥的密码时,才能替换旧链。如果未提供密码,并且私钥密码与密钥库密码不同,则会提示用户输入。
关于生成证书签名请求(CSR)和导入证书回复的更详细信息,请参阅文档:
- 带有 Windows 示例的 keytool 文档
- 带有 UNIX 示例的 keytool 文档
原文:
本课程展示如何使用、、和将文件放入 JAR(Java ARchive)文件,以便后续由工具进行签名。
本课程分为两部分。首先,您将创建和部署一个应用程序。其次,您将作为签名应用程序的接收者。
以下是创建和部署应用程序的步骤:
注意: 为方便起见,您假装是一个名为 Susan Jones 的用户/开发者。您需要在生成密钥时定义 Susan Jones。
- 将包含应用程序的 Java 类文件放入 JAR 文件中
- 对 JAR 文件进行签名
- 导出与用于签署 JAR 文件的私钥对应的公钥证书
以下是向应用程序授予权限的步骤
注意: 为方便起见,您假装是一个名为 Ray 的用户。
- 您可以看到,当在安全管理器下运行时,签名应用程序通常无法读取文件。
- 使用将证书导入 Ray 的密钥库中,别名为
- 使用策略工具在 Ray 的策略文件中创建一个条目,以允许由签名的代码读取指定文件。
- 最后,您将看到在安全管理器下运行的应用程序现在可以读取文件,因为已经被授予了相应的权限。
有关数字签名、证书、密钥库和工具的更多信息,请参阅用于安全代码和文件交换的 API 和工具使用课程。
重要: 您需要在存储示例应用程序的目录中执行本课程中的任务,但应将应用程序所需的数据文件存储在不同的目录中。本教程中的所有示例都假定您正在目录中工作,并且数据文件位于目录中。
如果您在 UNIX 系统上工作,请用您自己的目录名称替换。
以下是步骤:
- 代码签署者的步骤
- 代码接收者的步骤
原文:
Code Signer 执行以下步骤:
- 下载并尝试示例应用程序。
- 创建包含类文件的 JAR 文件,使用工具。
- 生成密钥(如果尚不存在),使用的命令。
可选步骤 为公钥证书生成证书签名请求(CSR),并导入认证机构(CA)的响应。为简单起见(并且因为你只是假装是苏珊·琼斯),这一步被省略了。有关更多信息,请参阅为公钥证书生成证书签名请求(CSR)。
- 对 JAR 文件进行签名,使用工具和私钥。
- 导出公钥证书,使用的命令。然后将签名的 JAR 文件和证书提供给接收者雷。
原文:
本课程使用我们提供给您的一个简单应用程序。
- 通过复制或下载源代码,在本地计算机上创建一个名为的文件。本课程中的示例假定您将放在目录中。
- 应用程序需要访问包含其将处理的数据的文本文件。下载一个,或使用任何其他方便的文本文件作为数据。
重要:将数据文件放入一个不同于包含已下载类文件的目录中。我们建议使用。
在本课程的后面部分,您将看到在安全管理器下运行的应用程序除非有明确的权限,否则无法读取文件。但是,应用程序始终可以从相同目录(或子目录)中读取文件。它不需要明确的权限。
- 编译然后运行应用程序以查看其功能。
当您运行应用程序时,您需要指定(作为参数)要读取的文件的路径名。
这里是一个示例运行:
原文:
接下来,在命令窗口中输入以下内容,创建一个包含文件的 JAR 文件:
这将创建一个名为的 JAR 文件,并将文件放入其中。
原文:
如果代码签名者尚未拥有适合签署代码的私钥,必须首先生成该私钥,以及一个相应的公钥,供代码接收方的运行时系统用于验证签名。
由于这节课假设你还没有这样的密钥,你将创建一个名为的密钥库,并创建一个带有新生成的公钥/私钥对的条目(其中公钥在证书中)。
在命令窗口中输入以下命令以创建一个名为的密钥库并生成密钥:
您将被提示输入密钥和密钥库的密码。
让我们看看的每个子部分的含义。
- 生成密钥的命令是*-genkey*。
- -alias signFiles子部分指示将来用于引用包含将生成的密钥的密钥库条目的别名。
- -keystore examplestore子部分指示您正在创建或已经使用的密钥库的名称(和可选路径)。
- 你被提示输入的storepass值指定了密钥库密码。
- 你被提示输入的keypass值指定了即将生成的私钥的密码。您始终需要此密码才能访问包含该密钥的密钥库条目。该条目不必有自己的密码。当提示您输入密钥密码时,您可以选择让它与密钥库密码相同。
注意:出于安全原因,您不应在命令行上设置密钥或密钥库密码,因为这样更容易被拦截。
如果您使用上述命令,将提示您输入您的专有名称信息。以下是提示信息;粗体表示您应该输入的内容。
命令在执行命令的同一目录中创建名为的密钥库(如果尚不存在)。该命令为具有 Susan Jones 作为通用名称和采购部门的实体生成公钥/私钥对。
该命令创建一个包含公钥和专有名称信息的自签名证书。(您提供的专有名称将用作证书中的“主题”字段。)该证书将在 90 天内有效,如果您不指定*-validity*选项,则为默认有效期。该证书与密钥库条目中的私钥关联,该条目由别名引用。
自签名证书对于开发和测试应用程序非常有用。然而,用户会收到警告,指出应用程序是使用不受信任的证书签名的,并询问他们是否要运行该应用程序。为了让用户更有信心地运行您的应用程序,请使用由认可的证书颁发机构颁发的证书。
注意: 如果接受选项的默认值或希望提示输入各种值,命令可能会更短。每当执行命令时,对于未指定具有默认值的选项,将使用默认值,并提示您输入任何必需的值。对于命令,具有默认值的选项包括别名(默认为)、有效期(90 天)和密钥库(位于您的主目录中名为的文件)。必需的值包括dname、storepass和keypass。
到此这篇java 在线教程(java在线教学)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/jjc/55448.html