Java Web应用开发中的安全技术:JCA与数据传输保护
1. JCA架构细节
JCA(Java Cryptography Architecture)是一种基于提供者的架构,借助密码服务提供者(CSP)模型可以实现实现独立性。下面深入探讨CSP及其架构细节。
1.1 密码服务提供者(CSP)
CSP提供了具体实现广告中宣传的密码算法的包。产品供应商的Java开发IDE/SDK通常默认安装并配置了一个或多个CSP。JCA提供了一组API,允许Java开发人员查询以确定提供者和密码服务信息,同时也方便应用程序开发人员添加额外的提供者。许多第三方提供者实现已经可用,可用于为Web应用程序开发强大的密码实现。
开发人员可以适当配置运行时环境,指定提供者的偏好顺序。偏好顺序是在未请求特定提供者时,搜索请求服务的提供者的顺序。这种架构使安全应用程序的开发变得简单方便。开发人员可以轻松请求特定类型的对象(如MessageDigest)和特定算法或服务(如MD5算法),从而访问已安装提供者之一的实现。例如:
md = MessageDigest.getInstance (“MD5”);
md = messageDigest.getInstance (“MD5”, “We45MD5”);
在实际的Java实现场景中,当应用程序请求MD5算法实现而不指定提供者名称时,CSP将按偏好顺序进行搜索,并返回提供该特定算法的第一个提供者的实现。如果指定了特定提供者,则返回该提供者的实现。
2. JCA的核心类、接口和算法
JCA的核心类、接口和算法可分类如下:
- 提供者和安全类
- 引擎类和算法
- 密钥接口和类
- 算法参数规范和密钥规范的类和接口
- 杂项和实用类
2.1 提供者和安全类
-
Provider类 :
java.security.Provider是所有安全提供者的基类。每个CSP都包含该类的一个实例,其中包含提供者的名称并列出其实现的所有安全服务/算法。该类代表Java安全API的“提供者”,提供者实现Java安全的部分或全部内容。提供者可能实现的服务子集包括算法(如DSA、MD5、RSA或SHA - 1)以及密钥生成、转换和管理设施。
| 方法 | 描述和备注 |
| — | — |
| elements() | 返回此哈希表中值的枚举 |
| entrySet() | 返回此提供者中包含的属性条目的不可修改的集合视图 |
| get(Object key) | 返回指定键映射到的值,如果此映射不包含该键的映射,则返回null |
| getInfo() | 以人类可读的格式返回提供者及其服务的描述 |
| getName() | 返回给定提供者的名称 |
| getProperty(String key) | 在此属性列表中搜索具有指定键的属性 |
| getService(String type, String algorithm) | 返回描述此提供者对指定类型的此算法或别名的实现的服务 |
| getServices() | 获取此提供者支持的所有服务的不可修改的集合 |
| getVersion() | 返回此提供者的版本号 |
| keys() | 返回此哈希表中键的枚举 |
| keySet() | 返回此提供者中包含的属性键的不可修改的集合视图 |
| load(InputStream inStream) | 从输入流中读取属性列表(键和元素对) |
| put(Object key, Object value) | 将键属性设置为具有指定的值 |
| putAll(Map<?,?> t) | 将指定映射中的所有映射复制到此提供者 |
| putService(Provider.Service s) | 添加服务 |
| remove(Object key) | 删除键属性(及其对应的值) |
| removeService(Provider.Service s) | 删除先前使用putService()添加的服务 |
| values() | 返回此提供者中包含的属性值的不可修改的集合视图 | -
Security类 :Security类管理已安装的提供者和安全范围的属性。它仅包含静态方法,从不实例化。添加或删除提供者以及设置安全属性的方法只能由受信任的程序执行。
| 方法 | 描述 |
| — | — |
| addProvider (Provider provider) | 将提供者添加到下一个可用位置 |
| getAlgorithmProperty (String algName, String propName) | 用于返回属性的值(现已弃用。建议使用新的基于提供者且与算法无关的AlgorithmParameters和KeyFactory引擎类) |
| getAlgorithms (String serviceName) | 返回包含指定Java密码服务的所有可用算法或类型名称的字符串集合 |
| getProperty (String key) | 返回给定键的属性值 |
| getProvider(String name) | 返回具有指定名称的已安装提供者(如果有) |
| getProviders() | 返回包含所有已安装提供者的数组 |
| getProviders (String filter) | 返回包含满足指定选择标准的所有已安装提供者的数组,如果没有安装此类提供者,则返回null对象 |
| insertProviderAt (Provider provider, int position) | 尝试在指定位置添加新的提供者 |
| removeProvider (String name) | 尝试删除具有指定名称的提供者 |
| setProperty (String key, String datum) | 尝试设置安全属性值 |
2.2 引擎类和算法
JCA(或JCE)中的引擎类旨在提供与特定密码算法或提供者无关的特定类型密码服务的接口。引擎提供以下功能之一:
- 密码操作(如加密、数字签名、消息摘要)
- 密码材料的生成器或转换器(如密钥和算法参数)
- 封装密码数据并可在更高抽象层使用的对象(如密钥库或证书)
引擎类包括:
- SecureRandom
- MessageDigest
- Signature
- Cipher
- Message Authentication Codes (MAC)
- KeyFactory/SecretKeyFactory
- KeyPairGenerator
- KeyGenerator
- KeyAgreement
- AlgorithmParameters
- AlgorithmParameterGenerator
- KeyStore
- CertificateFactory
- CertPathBuilder
- CertPathValidator
- CertStore
下面介绍几个重要的引擎类:
-
SecureRandom类
:在许多情况下,开发人员需要为对称算法生成密钥和初始化向量。
SecureRandom
类可帮助生成真正的随机数。它扩展了
Random
类,提供“密码学上强”的随机数生成器(RNG)。该类产生的随机数应满足联邦信息处理标准(FIPS)140 - 2中规定的统计随机数生成器测试,并且输出序列必须是密码学上强的。该类还可用于生成随机请求令牌,以防止跨站请求伪造(CSRF)。
-
MessageDigest类
:
java.security
包中的
MessageDigest
类是一个抽象类,扩展了
MessageDigestSpi
类。它为应用程序提供消息摘要算法服务,如MD5或SHA。消息摘要是安全的单向哈希函数,可将任何可变长度的明文转换为固定长度的哈希值。
消息摘要的处理过程如下:
MessageDigest
对象首先被初始化,数据通过
update()
、
reset()
和
digest()
等方法进行处理。信息使用一个或多个重载的
update()
方法进行处理,
reset()
方法可在任何时间重置摘要。所有数据更新完成后,应调用
digest()
方法之一完成哈希计算。调用
digest()
方法后,
MessageDigest
对象将重置为初始化状态。
为防止生日攻击或碰撞,建议使用盐进行哈希处理。盐是随机字节值,添加到哈希过程中以增加哈希值的随机性,确保其具有抗碰撞性。盐可以是64位值,可通过
update()
方法引入哈希过程,并可作为明文存储在哈希信息旁边,每个条目的盐值应不同。
-
Cipher类
:
Cipher
类提供加密和解密信息的密码功能,是JCE框架的核心。要实例化
Cipher
对象,应用程序开发人员调用其重载的
getInstance()
方法之一,并传入请求的“转换”名称。转换是一个字符串对象,描述对给定输入执行的操作(或一组操作)以产生输出,始终包含密码算法的名称(如DES),可能后跟反馈模式和填充方案。该类有许多实用方法,如
init()
、
update()
和
doFinal()
,可帮助执行各种加密/解密操作。
-
KeyFactory类
:
KeyFactory
类有助于构建密钥工厂。开发人员可以使用它生成公钥、私钥或进行转换。它可将不透明的密码密钥转换为密钥规范,反之亦然,具有双向性。在企业环境中,同一密钥可能存在多个兼容的密钥规范,此时密钥工厂可用于在兼容的密钥规范之间进行转换。
-
KeyGenerator类
:JCE的
KeyGenerator
类提供对称密钥生成功能。开发人员可以使用适当的
getInstance()
方法构造该类的对象,并且该对象可重复使用。JCE提供两种生成密钥的方式:算法特定的初始化和算法无关的初始化。算法特定的初始化有两个带有
AlgorithmParameterSpec
参数的
init()
方法;算法无关的初始化有三种不同类型的
init()
方法,共享密钥大小和随机源的概念。
2.3 密钥接口和类
java.security.Key
接口是所有“不透明”密钥的顶级接口,定义了所有不透明密钥对象共享的功能。不透明密钥表示无法直接访问构成密钥的“密钥材料”,通过
getAlgorithm()
、
getFormat()
和
getEncoded()
方法访问密钥材料。所有不透明密钥具有算法、编码形式和格式三个特征:
-
算法
:指特定密钥的加密算法,通常是对称(如AES、3DES、DES)或非对称操作算法(如DSA或RSA)。
-
编码形式
:当需要在Java虚拟机外部使用密钥的标准表示时,使用密钥的外部编码形式,密钥根据标准格式(如X.509或PKCS#8)进行编码,并通过
getEncoded()
方法返回。
-
格式
:编码密钥的格式名称,通过
getFormat()
方法返回。
在透明密钥表示中,可以通过相应密钥规范类中定义的
get()
方法之一单独访问每个密钥材料值。例如,
DSAPrivateKeySpec
类实现了
KeySpec
接口,指定了DSA私钥及其相关参数,具有
getX()
、
getP()
、
getQ()
和
getG()
等方法。同样,
RSAPrivateCrtKeySpec
类扩展了
RSAPrivateKeySpec
类,具有返回公指数和相关中国剩余定理信息值的方法。
3. 传输中数据的保护
我们知道,数据在系统中存储时需要保护,但同样重要的是,数据会被用户频繁访问并在网络中传输。攻击者为了窃取敏感信息,会采用各种手段嗅探网络数据,破坏传输数据的机密性和完整性。因此,在网络中传输的敏感信息也必须得到保护。数据通过公共和私有网络传输,攻击者使用简单的网络监控工具就能轻易获取传输中的信息,这些信息可能包括用户名、密码、信用卡信息、加密密钥等。这种攻击者嗅探网络流量并获取信息的攻击被称为中间人攻击。为了防止此类攻击,传输敏感信息的链路必须进行加密,确保信息在传输过程中不被嗅探。
3.1 安全套接层/传输层安全的历史
Web应用程序安全传输的标准实现是使用传输层安全(TLS),它的前身是安全套接层(SSL)。Netscape开发SSL的目的是在互联网上传输私有信息,SSL使用公钥和私钥进行操作,并借助数字证书实现。SSL为客户端与服务器之间的交互提供了加密链路。Netscape开发了SSL 1.0版本,1995年发布的SSL 2.0版本存在诸多缺陷,因此在1996年推出了SSL 3.0版本。随后,互联网工程任务组(IETF)接管了SSL,并将其命名为TLS,TLS成为了标准。1999年,Visa、MasterCard、American Express等主要支付品牌以及多家金融机构公开声明,电子商务交易应采用SSL/TLS作为安全措施。使用SSL/TLS保护的Web应用程序访问流量将通过超文本传输安全协议(HTTPS)进行,而不是未加密的常规HTTP协议。
为了在网络上提供安全的信息传输,SSL/TLS结合了多种加密过程。它实际上是对用于互联网通信的标准TCP/IP套接字协议的安全增强。安全套接层位于标准TCP/IP协议栈的传输层和应用层之间,如下所示:
graph LR
A[应用层] --> B[SSL/TLS]
B --> C[传输层]
C --> D[网络层]
D --> E[接口层]
最常用于SSL的Web应用程序协议是超文本传输协议(HTTP),即互联网网页使用的协议。
3.2 SSL/TLS握手过程
SSL/TLS在不同阶段使用多种加密过程进行安全数据传输。例如,SSL使用公钥加密进行身份验证,使用私钥加密和数字签名来保护信息和隐私。SSL/TLS通信始于客户端和服务器之间的一系列信息交换,这一系列信息交换被称为SSL握手。SSL/TLS握手确保了密码套件的协商、身份验证以及加密算法的确定,从而建立信息安全。
在SSL数据传输模式下,客户端和服务器之间会交换一系列消息,具体步骤如下:
1.
获取SSL/TLS证书
:Web应用程序供应商或组织向证书提供商提交证书签名请求,该请求包含Web应用程序/网站的名称、联系电子邮件地址和公司信息。证书提供商审核请求后进行签名,生成公钥证书。当用户连接到Web应用程序/网站时,公钥证书会在握手过程中提供给浏览器。证书包含网站/应用程序的详细信息、组织名称、证书序列号、证书类别、证书提供商以及证书的有效期。
2.
客户端发起请求(Client Initiation)
:客户端发起SSL/TLS请求,包括SSL版本和支持的密码套件列表,此步骤在SSL/TLS术语中称为ClientHello。密码套件信息包括加密算法和密钥大小,例如TLS_RSA_WITH_RC4_128_MD5,其中RSA用于密钥交换和证书验证,RC4用于消息加密,MD5用于验证消息内容。
3.
服务器确认(Server Acknowledgement)
:服务器收到客户端请求后,选择客户端和服务器都支持的最高版本的SSL/TLS和最合适的密码套件,并将此信息返回给客户端,此步骤称为ServerHello。
4.
发送证书(Send Certificate)
:可选步骤,服务器可以向客户端发送证书(或证书链)。如果需要进行身份验证,此步骤是必需的。证书链从服务器的公钥证书开始,以证书颁发机构的根证书结束,此步骤在SSL/TLS术语中称为“certificate”。
5.
请求证书(Request Certificate)
:可选步骤,如果步骤3因身份验证要求而必须执行,服务器需要对客户端进行身份验证,会向客户端发送证书请求,此步骤称为“certificate request”。
6.
服务器密钥交换(Server Key Exchange)
:如果步骤3中发送的公钥信息不足以进行密钥交换,服务器会向客户端发送服务器密钥交换消息。
7.
服务器准备就绪(Server Ready)
:服务器向客户端表示其初始协商消息已成功完成,此步骤称为ServerHello Done。
8.
发送证书(Send Certificate)
:如果服务器在步骤4中请求了客户端证书,客户端会像服务器在步骤3中那样发送其证书链,此步骤同样称为“certificate”。
9.
客户端密钥交换(Client Key Exchange)
:客户端生成用于对称加密的密钥信息,对于RSA算法,客户端使用服务器的公钥对该密钥信息进行加密并发送给服务器。
10.
证书验证(Certificate Verification)
:可选步骤,当客户端在步骤7中提供了证书时发送此消息,目的是让服务器完成对客户端的身份验证。客户端使用加密哈希函数对信息进行数字签名,服务器使用客户端的公钥解密该信息以验证客户端身份。
11.
更改密码规范(Change Cipher Spec)
:客户端向服务器发送消息,指示切换到加密模式。
12.
服务器端握手建立(Handshake Establishment on Server Side)
:客户端通知服务器已准备好开始安全数据通信。
整个SSL/TLS握手过程可以用以下流程图表示:
graph LR
A[客户端发起请求] --> B[服务器确认]
B --> C{是否发送证书}
C -- 是 --> D[发送证书]
C -- 否 --> E[请求证书?]
D --> E
E -- 是 --> F[请求证书]
E -- 否 --> G[服务器密钥交换?]
F --> G
G -- 是 --> H[服务器密钥交换]
G -- 否 --> I[服务器准备就绪]
H --> I
I --> J{是否请求客户端证书}
J -- 是 --> K[客户端发送证书]
J -- 否 --> L[客户端密钥交换]
K --> L
L --> M{是否需要证书验证}
M -- 是 --> N[证书验证]
M -- 否 --> O[更改密码规范]
N --> O
O --> P[服务器端握手建立]
通过以上对JCA架构和数据传输保护的介绍,我们可以看到Java在Web应用开发中提供了丰富的安全技术来保护数据的安全。无论是在本地存储数据时使用JCA进行加密,还是在数据传输过程中使用SSL/TLS进行保护,都能有效防止数据泄露和攻击,确保Web应用程序的安全性。
超级会员免费看
265

被折叠的 条评论
为什么被折叠?



