许梦微,王希胤
(华北理工大学理学院,河北 唐山 063210)
Apache Shiro 的开发旨在简化保护Java应用程序的过程,并提供灵活且易于使用的安全解决方案。Shiro可以轻松地与众多Java技术集成,且提供广泛的功能和选项,允许开发人员定制以满足安全需求,它因强大灵活、简单易用的特点,受到广泛应用[1]。Shiro的主要特性包括:
1) 身份验证:Shiro提供的身份验证API可以根据各种类型的数据源(如数据库、LDAP 和Active Directory) 对用户进行身份验证[2]。
2) 授权:Shiro的授权框架允许开发人员在细粒度级别上指定访问控制,如对应用程序中特定页面或特性的访问[3]。
3) 会话管理:Shiro提供的会话管理API允许开发人员管理用户会话,包括会话超时、会话集群和会话验证。
4) 加密:Shiro 强大的加密API,可用于哈希和加密密码,并生成安全的随机数[4]。
5) Web支持:Shiro包含许多专为Web应用程序设计的特性,例如对安全Cookie的支持、CSRF的预防以及与流行的Web 框架(如Apache Struts 和Spring MVC) 的集成。
Shiro架构主要包括的组件和功能如表1所示[5]:
表1 Shiro架构组件说明
加密是使用算法和密钥将明文转换为密文的过程,产生的密文只能由拥有密钥的人解密和读取。Shiro提供加密作为一种保护敏感数据的方法,主要用于密码存储和数据保护,即可以在用户密码存储到数据库之前进行加密,以防止攻击者利用安全漏洞获得密码访问权;或通过加密保护其他通过网络传输或存储在文件中的敏感数据(如信用卡号码)。Shiro 的加密功能可以确保这些数据保持机密性,且不会被未经授权的各方访问。
Shiro 提供各种加密功能以确保安全通信和数据存储,可以应用在密码加密、会话加密、数据加密、消息加密等场景。密码加密时,Shiro 的PasswordService接口可以在密码存储到数据库之前安全地散列和加盐,保障即使数据泄露的情况下,密码也不会被窃取。使用Shiro 对会话数据进行加密和解密,可以确保在遭受会话劫持攻击时不泄露用户敏感数据。Shiro 用于敏感数据存储和传输的加密以及应用程序或系统之间发送消息的加密,可以确保数据不被未授权的攻击者拦截或读取。
Shiro 支持多种加密算法和多种操作模式(如ECB、CBC、CFB、OFB等),支持密钥管理和密钥生成,以及加盐和哈希处理,这使安全管理密钥变得容易,并进一步增强了数据安全性。要在Shiro中使用加密功能,首先需要配置一个加密密钥,用于对数据加密和解密。Shiro提供了多种配置加密密钥的方法,包括生成随机密钥、将密钥指定为字符串或从文件加载密钥。密钥配置后,就可以使用它和Shiro提供的API来加密和解密数据。为了确保加密的数据得到适当的保护,安全地存储密钥、控制对密钥的访问,使用强加密算法,注意密钥长度也非常重要。
Shiro 支持多种加密算法,包括:对称加密(如AES、DES 和Blowfish) 、非对称加密(如RSA) 、哈希算法(如MD5、SHA-1、SHA-256 等)和MAC(如HMACSHA1、HMAC-SHA256) 。其中,对称加密算法使用一个共享密钥来加密和解密数据,而非对称加密算法使用一对密钥,一个公钥用于加密,一个私钥用于解密。哈希算法是将明文消息转换为固定长度的哈希值,常用于密码存储和验证。MAC(Message Authentication Code) ,即消息验证码,它是使用一个密钥生成一个MAC 值,与消息一起发送,接收端再使用相同的密钥生成MAC值,与接收到的MAC值进行比较的过程,主要用于验证消息的完整性。Shiro 中常用的加密算法和技术有:
1) AES:AES是一种对称密钥加密算法,使用分组密码对128位的数据块进行加密和解密,具有较高安全性。
2) RSA: 它基于大数因式分解的困难性被广泛应用于数据的安全传输加密。
3) SHA:SHA 是一系列用于提供数据完整性和身份验证的加密哈希函数,通过对输入数据生成唯一固定大小的输出哈希值,来验证数据的真实性。
4) Blowfish:Blowfish 是一种对称的分组加密算法,加密快速且可提高安全性级别,使用的密钥长度可变,最高可达448位。
Shiro 中CipherService 接口定义了用于加密和解密数据、生成加密密钥和计算校验和的方法。CipherService 根据算法的要求,使用一个CipherKey 来实现生成各种大小的加密密钥,主要是生成随机字节。Shiro 中CipherKey 的实现,包括AesCipherKey、BlowfishCipherKey 和CamelliaCipherKey。要使用CipherService 生成密钥,需要实例化并调用generate-NewKey() 方法。通过创建CipherService 的实例能实现加密和解密功能,同时还可以配置所需的加密算法和密钥长度,CipherService.generateNewKey() 方法可用于生成一个指定大小和算法的新密钥。
Shiro利用其内置的加密支持,提供了一种简单而灵活的方式来安全存储密钥。通过使用强加密算法或向哈希加盐可以提高密钥破解的难度,通过加密安全随机数生成器(SecureRandom) 生成随机值可以确保密钥不被轻易预测。Shiro 还提供了密钥存储库作为存储加密密钥和证书的安全容器,支持各种密钥存储格式,包括Java keystore(JKS) 、PKCS# 12 和JCEKS。此外,Shiro 还提供密钥派生,通过使用密钥派生函数(Key Derivation Function, KDF) 从主密钥生成加密密钥。KDF可将密钥和一组参数作为输入,生成一个或多个可用于加密或解密的派生密钥。Shiro 支持多种KDFs,包括PBKDF2、bcrypt 和scrypt,这些KDFs 使用盐和多轮散列来减缓暴力攻击。在这些方法中,具体选择取决于应用程序的要求和Shiro环境的配置。通常在Java 中,Shiro 用Java Cryptography Architecture(JCA) 提供强大的加密算法和密钥管理,还可将密钥存储和管理转移到专用的硬件或软件,来提供密钥管理解决方案。并且Shiro 设计为一个可插拔的架构,允许用户自定义密钥管理,并通过实现适当的访问控制和备份策略安全地存储加密密钥。
1) 创建加密密钥:在Apache Shiro中,可以使用接口定义密钥Key,通过密钥生成器来创建随机密钥或自定义配置。下面是在Java中创建密钥的代码:
2) 配置加密算法:CipherService 接口提供了一组创建和操作密码的方法,可以使用DefaultCipherService 实现或自定义配置加密算法。这里采用AES 加密算法作为示例:
3) 加密数据:创建密钥并配置加密算法后,就可以使用CipherService 来加密数据,通常需要创建一个Cipher实例,对要加密的数据和密钥调用encrypt方法进行加密。
4) 解密数据:要解密加密数据,需要使用与加密相同的密钥,创建一个Cipher实例并调用decrypt方法解密。
在此例中实现了通过Shiro 使用AES 算法加密的功能,首先,使用类定义了一个密码密钥AesCipher-Key,然后创建了一个DefaultCipherService并设置了密码算法和密钥大小,最后,使用encrypt 方法加密敏感数据,decrypt方法解密数据[6]。
Shiro的加密功能在保护敏感数据方面,常用于密码存储,而在一个应用程序中,对用户密码进行加密保护,常伴随用户的身份认证与授权,图1 是Shiro 实现登录、认证、授权的大概流程。
图 1 Shiro实现登录、认证、授权的流程
MD5是一种广泛使用的哈希算法,是验证数据完整性和确保数据在传输过程中没有被篡改或损坏的重要工具。它单向哈希的特点对存储密码等敏感信息非常有用,因为存储的是哈希值而不是实际数据。当用户输入密码时,使用MD5 算法对其进行哈希,并将得到的哈希值与存储的哈希值进行比较,如果匹配,才授予用户访问权限。下面以MD5 算法为例,说明使用Shiro对用户密码加密的过程。
1) 将 Apache Shiro 添加到项目的依赖项中,通过将以下内容添加到项目的pom.xml文件中实现。
2) 通过创建Shiro INI 文件或编程来配置 Apache Shiro。下面是配置安全管理器和myRealm 的Shiro INI文件示例:
main文件
myRealm文件
其中,INI 文件中配置了一个使用myRealm 领域的securityManager。myRealm 领域在com.example.My-Realm类中定义,并被配置为使用MD5作为散列算法和单个散列迭代的HashedCredentialsMatcher。
3) 定义一个将对用户进行身份验证并授权其操作的领域,负责检查用户的凭据,包括它们的密码[7]。下面是一个基于用户名和密码对用户进行身份验证的示例。
4) 自定义的身份验证策略,使用MD5加密将用户提交的密码与存储在用户账户中的密码进行比较。下面是一个修改doGetAuthenticationInfo() 方法以使用MD5加密的例子:
通过对Shiro加密机制的研究,实现了用Shiro框架加密数据。用Shiro对用户密码这一敏感数据进行加密,既易于实现,又能灵活配置和集中管理,既能防止未经授权的访问,又确保了用户密码的私有与安全。