也许没有比应用程序安全更重要的软件工程主题。 攻击是昂贵的,无论是来自内部还是外部,而且某些攻击可能会使软件公司承担赔偿责任。 随着计算机(尤其是Internet)技术的发展,安全攻击变得越来越复杂和频繁。 掌握最新技术和工具是应用程序安全的关键之一。 另一个是成熟的技术的坚实基础,例如数据加密,身份验证和授权。
Java平台(包括基本语言和库扩展)为编写安全的应用程序奠定了良好的基础。 本教程介绍了密码学的基础知识以及如何用Java编程语言实现密码学,并提供了示例代码来说明这些概念。
在分两部分的教程的第一部分中,我们介绍了库扩展(现在是JDK 1.4基础的一部分)中的资料,这些扩展称为Java密码术扩展(JCE)和Java安全套接字扩展(JSSE)。 另外,本教程介绍了CertPath API,它是JDK 1.4的新增功能。 在第2部分(请参阅参考资料 )中,我们将扩大讨论范围以涵盖访问控制,访问控制由Java身份验证和授权服务(JAAS)在Java平台中进行管理。
这是一个中级教程。 它假定您知道如何读写基本的Java程序,包括应用程序和applet。
如果您已经是Java程序员,并且对加密技术(诸如私钥和公钥加密,RSA,SSL,证书等主题)以及支持它们的Java库(JCE,JSSE)感到好奇,那么本教程适合您。 它不假定密码学,JCE或JSSE具有任何以前的背景。
本教程介绍了基本的密码构建块概念。 每个概念后都有Java实现注意事项,代码示例以及示例执行的结果。
您需要以下各项来完成本教程中的编程练习:
您可以使用JDK 1.3.x,但必须自己安装JCE和JSSE。
这些代码示例将加密的数据直接转储到屏幕上。 在大多数情况下,这将导致外观怪异的控制字符,其中某些字符有时可能会导致屏幕格式问题。 这不是一个好的编程习惯(最好将它们转换为可显示的ASCII字符或十进制表示形式),但是此处已这样做是为了保持代码示例及其输出简短。
在大多数情况下,在示例执行部分中,实际字符串已被修改为与本教程的字符集要求兼容。 同样,在大多数示例中,我们查找并显示用于给定算法的实际安全提供程序库。 这样做是为了使用户更好地了解针对哪些函数调用了哪些库。 为什么? 因为在大多数安装中,安装了许多这些提供程序。
Java编程语言和环境具有许多有助于安全编程的功能:
简而言之,可以使用多种编程样式和技术来帮助确保更安全的应用程序。 考虑以下两个一般示例:
String
对象中,则密码将保留在内存中,直到被垃圾回收或过程结束为止。 如果是垃圾回收,它将一直存在于可用内存堆中,直到重新使用内存空间为止。 密码String
在内存中保留的时间越长,它越容易受到监听。 String
分页到磁盘的交换空间,因此容易受到磁盘块监听的攻击。 char
数组中,并在使用后将其归零。 ( String
是不可变的,因此您不能将它们归零。) transient
关键字标记属性,以便在流中将其跳过。 在整个教程中,当我们需要这些技术时,我们将更详细地讨论它们。
在JDK 1.4之前,必须将许多安全功能作为扩展添加到基本Java代码发行版中。 美国严格的出口限制要求这种功能分离。
现在,新的宽松法规为更紧密地集成安全功能和基本语言打开了大门。 以下软件包(在1.4版本之前用作扩展)现已集成到JDK 1.4中:
JDK 1.4还引入了两个新功能:
JCE,JSSE和CertPath API是本教程的主题。 在本系列的下一个教程中,我们将重点介绍JAAS。 这两个教程都没有涵盖JGSS(它提供了一个通用框架来在应用程序之间安全地交换消息)。
我们可以使用第三方库(也称为provider)来增强当前Java语言中已经丰富的功能集。 提供程序添加其他安全算法。
作为图书馆的一个例子,我们将与充气城堡提供商合作(参见相关主题 )。 Bouncy Castle库提供了其他加密算法,包括什么是公钥加密中讨论的流行的RSA算法。 和什么是数字签名? 本教程。
虽然目录名称和java.security文件可能有所不同,但这是用于安装Bouncy Castle提供程序的模板。 要安装此库,请下载bcprov-jdk14-112.jar文件并将其放置在j2sdk1.4.0 \ jre \ lib \ ext和Program Files \ Java \ J2re1.4.0 \ lib \ ext目录中。 在与上面相同的目录中的两个java.security文件中,但使用“ security”而不是“ ext”,添加以下行:
security.provider.6=org.bouncycastle.jce.provider.BouncyCastleProvider
到这行代码的末尾:
security.provider.1=sun.security.provider.Sun
security.provider.2=com.sun.net.ssl.internal.ssl.Provider
security.provider.3=com.sun.rsajca.Provider
security.provider.4=com.sun.crypto.provider.SunJCE
security.provider.5=sun.security.jgss.SunProvider
security.provider.6=org.bouncycastle.jce.provider.BouncyCastleProvider
在本节中,我们介绍了Java语言提供的功能(完全集成或基于扩展),这些功能有助于确保编程保持安全。 我们提供了一些安全编程技术的一般示例,以帮助您熟悉该概念。 我们介绍了曾经是扩展程序但现在已集成到1.4版发行中的安全技术。 我们还注意到了两种新的安全技术。 而且我们已经证明,第三方库可以通过提供新技术来增强安全程序。
在本教程的其余部分,我们将使您熟悉这些旨在提供安全消息传递的概念(因为它们适用于Java编程):
在讨论每个主题时,我们将提供示例和示例代码。
在本节中,我们将学习消息摘要,这些摘要将消息中的数据带入并生成一个位块,用于表示消息的“指纹”。 我们还将介绍与消息摘要有关的JDK 1.4支持的算法,类和方法,为消息摘要和消息身份验证功能提供代码示例和示例执行代码。
消息摘要是一种确保消息完整性的功能。 消息摘要将一条消息作为输入,并生成通常代表几百位长的位块,以表示消息的指纹。 消息中的微小变化(例如,闯入者或窃听者)使指纹产生了明显的变化。
消息摘要功能是单向功能。 从消息中生成指纹是一件简单的事情,但是要生成与给定指纹匹配的消息则相当困难。
消息摘要可以弱也可以强。 校验和(即消息所有字节的XOR)是弱消息摘要功能的示例。 修改一个字节以生成任何所需的校验和指纹很容易。 最强大的功能使用哈希。 消息中的1位更改会导致指纹发生巨大变化(理想情况下,指纹位的50%会发生变化)。
JDK 1.4支持以下消息摘要算法:
MD5和SHA-1是最常用的算法。
MessageDigest
类可操纵消息摘要。 消息摘要代码示例中使用了以下方法:
MessageDigest.getInstance("MD5")
:创建消息摘要。 .update(plaintext)
:使用纯文本字符串计算消息摘要。 .digest()
:读取消息摘要。 如果将密钥用作消息摘要生成的一部分,则该算法称为消息身份验证码 。 JDK 1.4支持HMAC / SHA-1和HMAC / MD5消息认证代码算法。
Mac
类使用KeyGenerator
类产生的密钥来操作消息验证代码。 在消息身份验证代码示例中使用以下方法:
KeyGenerator.getInstance("HmacMD5")
和.generateKey()
:生成密钥。 Mac.getInstance("HmacMD5")
:创建一个MAC
对象。 .init(MD5key)
:初始化MAC
对象。 .update(plaintext)
和.doFinal()
:使用纯文本字符串计算MAC
对象。 import java.security.*;
import javax.crypto.*;
//
// Generate a Message Digest
public class MessageDigestExample {
public static void main (String[] args) throws Exception {
//
// check args and get plaintext
if (args.length !=1) {
System.err.println("Usage: java MessageDigestExample text");
System.exit(1);
}
byte[] plainText = args[0].getB