shiro进行解密

目录

      • Shiro 解密的核心注意事项
        • 1. 密码处理:坚决避免 “可逆解密”
        • 2.例子【自己模拟数据库,未连数据库】:

Shiro 解密的核心注意事项

1. 密码处理:坚决避免 “可逆解密”
  • 禁用明文存储:永远不要将明文密码存入数据库,必须使用 Hash 算法 + 盐值 加密(盐值需每个用户唯一,避免彩虹表攻击);
  • 不自定义解密逻辑:不要尝试对 Hash 后的密码进行 “解密”(不可逆算法无法解密),验证时只需用相同算法和盐值加密输入密码后对比;
  • 选择强 Hash 算法:优先使用 SHA-256、SHA-512 等强算法,避免使用 MD5(安全性较低,仅用于兼容旧系统),且需设置足够的迭代次数(如 10000+)。

2. 对称加密:密钥安全是核心
密钥长度合规:AES 算法需使用 16/24/32 字节的密钥(对应 AES-128/AES-192/AES-256),密钥长度不足会导致加密强度下降;
密钥安全存储:密钥绝对不能硬编码到代码中,需通过配置中心(如 Nacos、Apollo)、硬件加密机(HSM)、环境变量等安全方式存储;
加密参数一致:解密时的 算法(AES/Blowfish)、模式(CBC/ECB)、填充方式(PKCS5Padding)、编码格式(Base64/Hex) 必须与加密时完全一致,否则会解密失败。
3. 令牌安全:防止令牌泄露与篡改
RememberMe 令牌保护
配置 secure=true(仅通过 HTTPS 传输 Cookie)和 httpOnly=true(禁止前端 JS 访问 Cookie,防止 XSS 攻击);
定期更换 rememberMe 密钥,避免密钥泄露导致令牌被解密;
JWT 令牌保护
使用非对称加密(RSA)进行签名(私钥加密签名,公钥验签),避免对称密钥泄露风险;
缩短 JWT 有效期(如 15 分钟),通过刷新令牌机制延长会话,减少令牌泄露后的风险。
4. 异常处理:避免泄露敏感信息
解密失败时(如密钥错误、密文篡改),仅返回通用错误提示(如 “认证失败”),不要暴露具体原因(如 “密钥错误”“密文格式错误”),防止攻击者通过异常信息猜测加密逻辑;
捕获 AuthenticationException 等 Shiro 认证异常时,避免打印详细堆栈(尤其是包含密钥、密文的日志)。
5. 版本与依赖:避免安全漏洞
使用 Shiro 最新稳定版本(如 1.12.0),旧版本(如 1.3.2,你日志中使用的版本)存在已知安全漏洞(如 RememberMe 反序列化漏洞);
若集成第三方库(如 JJWT、SLF4J),需确保依赖版本无安全漏洞(可通过 Maven Dependency Check 等工具检测)。
四、常见问题排查
密码验证失败(如你日志中的 “用户名或密码错误”):
检查盐值是否一致(存储时和验证时的盐值必须相同);
检查 Hash 算法、迭代次数、编码格式是否匹配;
确认数据库中存储的加密密码是否正确(可手动用相同算法加密明文密码对比)。
对称解密失败:
核对密钥是否与加密时一致(包括密钥长度、编码格式);
检查加密模式(CBC/ECB)、填充方式(PKCS5Padding)是否匹配;
确认密文是否完整(未被篡改、编码格式正确)。
RememberMe 令牌解密失败:
检查 rememberMeManager 的 cipherKey 是否正确;
确认 Cookie 是否被篡改(如前端修改 Cookie 内容);
升级 Shiro 版本,避免旧版本反序列化漏洞。

2.例子【自己模拟数据库,未连数据库】:
[main]
definitionRealm=com.apesource.shiro.realm.MyRealm
securityManager.realms=$definitionRealm

工具类:DigestsUtil

package com.apesource.shiro.tools;import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;import java.util.HashMap;
import java.util.Map;/*** @Description:摘要*/
public class DigestsUtil {public static final String SHA1 = "SHA-1";//加密方式public static final Integer COUNTS =369;//加密次数/*** @Description sha1方法* @param input 需要散列字符串* @param salt 盐字符串* @return*/public static String show(String input, String salt) {return new SimpleHash(SHA1, input, salt,COUNTS).toString();}/*** @Description 随机获得salt字符串* @return*/public static String generateSalt(){SecureRandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();return randomNumberGenerator.nextBytes().toHex();}/*** @Description 生成密码字符密文和salt密文* @param* @return*/public static Map<String,String> entryptPassword(String passwordPlain) {Map<String,String> map = new HashMap<String,String>();String salt = generateSalt();String password =show(passwordPlain,salt);map.put("name","刘老师");map.put("salt", salt);map.put("password", password);//密文return map;}
}

业务层代码:

package com.apesource.shiro.service;import java.util.Map;/*** @Description:模拟数据库操作服务接口*/
public interface SecurityService {/*** @Description 查找用户密码* @param loginName 用户名称* @return 密码*/Map<String,String> findPasswordByLoginName(String loginName);
}
package com.apesource.shiro.service.impl;import com.apesource.shiro.service.SecurityService;
import com.apesource.shiro.tools.DigestsUtil;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;import java.util.HashMap;
import java.util.Map;/*** @Description:模拟数据库操作服务接口实现*/
public class SecurityServiceImpl implements SecurityService {public Map<String,String> findPasswordByLoginName(String loginName) {//1.获取dao对象//2.调用dao方法(按照用户名称查询用户信息,匿名密码)//按照用户名查询数据库加密的密码,模拟数据库if (loginName.equals("刘老师")){//模拟数据库Map<String, String> stringStringMap = DigestsUtil.entryptPassword("654321");return stringStringMap;}return null;}
}

MyRealm:

package com.apesource.shiro.realm;import com.apesource.shiro.service.SecurityService;
import com.apesource.shiro.service.impl.SecurityServiceImpl;
import com.apesource.shiro.tools.DigestsUtil;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;import java.util.Map;public class MyRealm extends AuthorizingRealm {//告诉shiro使用的散列算法public MyRealm() {//MyRealm的无参构造,构造初始值//指定密码匹配方式sha1HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(DigestsUtil.SHA1);//指定密码迭代此时hashedCredentialsMatcher.setHashIterations(DigestsUtil.COUNTS);//使用父层方法是匹配方式生效setCredentialsMatcher(hashedCredentialsMatcher);}/*** @Description 认证方法*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//获取登录名//1.构造uptokenUsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;//2.获取输入的用户名密码String username = upToken.getUsername();//3.通过用户名称查询数据库相关信息SecurityService securityService = new SecurityServiceImpl();//创建业务对象//4.调用业务方法(按照用户名称查询用户相关信息)Map<String, String> map = securityService.findPasswordByLoginName(username);if(map == null){throw  new UnknownAccountException("账户不存在");}String salt = map.get("salt");//从map集合中获取盐值String password = map.get("password");//从map集合中获取匿名密码//参数1:安全数据   参数2:密码   参数3:混淆字符串(盐值)  参数4:realm名称return new SimpleAuthenticationInfo(username,password, ByteSource.Util.bytes(salt),"myRealm");}/*** @Description 授权方法*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}}

测试类:

package com.apesource.shiro;import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;/*** @Description:shiro的第一个例子*/
public class HelloShiro {@Testpublic void shiroLogin(){//导入INI配置创建工厂Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");//工厂构建安全管理器SecurityManager securityManager = factory.getInstance();//使用工具生效安全管理器SecurityUtils.setSecurityManager(securityManager);//使用工具获得subject主体Subject subject = SecurityUtils.getSubject();String name = "刘老师";String password = "654321";//构建账户密码UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(name,password);//使用subject主体去登录subject.login(usernamePasswordToken);//打印登录信息System.out.println("登录结果:"+subject.isAuthenticated());//true}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/94678.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/94678.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

更改 Microsoft Edge 浏览器的缓存与用户数据目录位置

Microsoft Edge浏览器默认会将缓存文件和用户数据存储在系统盘&#xff08;通常是C盘&#xff09;&#xff0c;随着使用时间的增长&#xff0c;这些文件可能会占用大量空间。本文将详细介绍多种更改Edge浏览器缓存位置和用户数据目录位置的方法&#xff0c;帮助您更好地管理磁盘…

【传奇开心果系列】Flet框架实现的图形化界面的PDF转word转换器办公小工具自定义模板

let框架实现的图形化界面的PDF转word转换器办公小工具自定义模板一、效果展示截图二、PDF转Word转换器概括介绍三、功能特性四、安装依赖五、运行程序六、使用说明七、注意事项八、技术栈九、系统要求十、源码下载地址 一、效果展示截图二、PDF转Word转换器概括介绍 一个基于Fl…

STM32 定时器(PWM输入捕获)

以下是基于STM32标准库&#xff08;以STM32F103为例&#xff09;实现PWM输入模式&#xff08;自动双沿捕获&#xff09;的完整代码&#xff0c;通过配置定时器的PWM输入模式&#xff0c;可自动捕获外部PWM信号的周期&#xff08;频率&#xff09;​和占空比&#xff0c;无需手动…

Web安全开发指导规范文档V1.0

一、背景 团队最近频繁遭受网络攻击,引起了部门技术负责人的重视,笔者在团队中相对来说更懂安全,因此花了点时间编辑了一份安全开发自检清单,觉得应该也有不少读者有需要,所以将其分享出来。 二、编码安全 2.1 输入验证 说明 检查项 概述 任何来自客户端的数据,如URL和…

在Godot中为您的游戏添加并控制游戏角色的完整技术指南

这是一个在Godot中为您的游戏添加并控制玩家角色的完整技术指南。这个过程分为三大步&#xff1a;​准备资源、构建场景、编写控制脚本。道可道&#xff0c;非常道&#xff0c;名可名&#xff0c;非常名&#xff01;第一步&#xff1a;准备资源&#xff08;建模与动画&#xff…

Flink 状态 RocksDBListState(写入时的Merge优化)

RocksDBListState<K, N, V> RocksDBListState 继承自 AbstractRocksDBState<K, N, List<V>>&#xff0c;并实现了 InternalListState<K, N, V> 接口。继承 AbstractRocksDBState: 这意味着它天然获得了与 RocksDB 交互的底层能力&#xff0c;包括&…

zookeeper-保姆级配置说明

一. 基本配置&#xff1a;clientPort&#xff1a; 客户端连接的服务器所监听的tcp端口&#xff0c;默认2181dataDir&#xff1a;内存数据库保存的数据路径。myid也存放在这个目录下&#xff0c;数据以异步方式写入。dataLogDir&#xff1a;事务日志存放路径。服务在确认一个事务…

半小时打造七夕传统文化网站:Qoder AI编程实战记录

背景 最近七夕到了&#xff0c;恰逢Qoder上线&#xff0c;萌生了一个想法&#xff0c;写一个以中国传统七夕为主题的网站。 七夕中国传统情人节 Qoder 介绍 Qoder 是阿里巴巴推出的一款旨在提升开发效率的 AI 编程平台。它通过上下文工程技术和智能体辅助&#xff0c;帮助开…

常见的 Loader 和 Plugin?

Loader: babel-loader&#xff1a;将ES6的代码转换成ES5的代码。css-loader&#xff1a;解析CSS文件&#xff0c;并处理CSS中的依赖关系。style-loader&#xff1a;将CSS代码注入到HTML文档中。file-loader&#xff1a;解析文件路径&#xff0c;将文件赋值到输出目录&#xff0…

设计模式学习笔记-----抽象策略模式

抽象策略模式由五个核心组件组成策略接口定义所有策略的统一规范&#xff0c;是策略模式的 "契约"mark()&#xff1a;策略的唯一标识&#xff08;类似字典的 key&#xff09;&#xff0c;默认返回 null&#xff0c;需具体策略实现类重写&#xff08;如InterviewSubje…

RabbitMQ面试精讲 Day 30:RabbitMQ面试真题解析与答题技巧

【RabbitMQ面试精讲 Day 30】RabbitMQ面试真题解析与答题技巧 开篇&#xff1a;系列收官之作&#xff0c;直击面试核心 今天是“RabbitMQ面试精讲”系列的第30天&#xff0c;也是本系列的收官之作。经过前29天对RabbitMQ核心概念、高级特性、集群架构、性能调优与开发运维的系…

Coze Studio开源版:AI Agent开发平台的深度技术解析- 入门篇

Coze Studio开源版&#xff1a;AI Agent开发平台的深度技术解析 引言 在人工智能快速发展的今天&#xff0c;AI Agent&#xff08;智能体&#xff09;已成为连接大语言模型与实际应用场景的重要桥梁。然而&#xff0c;构建一个功能完整、性能稳定的AI Agent开发平台并非易事&am…

一文了解 DeepSeek 系列模型的演进与创新

近年来&#xff0c;DeepSeek 团队在大语言模型&#xff08;LLM&#xff09;领域持续发力&#xff0c;围绕模型架构、专家路由、推理效率、训练方法等方面不断优化&#xff0c;推出了一系列性能强劲的开源模型。本文对 DeepSeek 系列的关键论文进行了梳理&#xff0c;帮助大家快…

开源大模型本地部署

一、大模型 T5\BERT\GPT → Transformer的儿子→自注意力机制神经网络 大模型&#xff0c; Large Model&#xff0c;是指参数规模庞大、训练数据量巨大、具有强泛化能力的人工智能模型&#xff0c;典型代表如GPT、BERT、PaLM等。它们通常基于深度神经网络&#xff0c;特别是T…

DAY 57 经典时序预测模型1

知识点回顾 序列数据的处理&#xff1a; 处理非平稳性&#xff1a;n阶差分处理季节性&#xff1a;季节性差分自回归性无需处理 模型的选择 AR(p) 自回归模型&#xff1a;当前值受到过去p个值的影响MA(q) 移动平均模型&#xff1a;当前值收到短期冲击的影响&#xff0c;且冲击影…

贪吃蛇游戏(纯HTML)

一、游戏截图二、源码 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>离谱贪吃蛇</title>…

InnoDB详解2

InnoDB详解2一.行结构1.结构图2.InnoDB支持的数据行格式1&#xff09;查看当前数据库或表的行格式2&#xff09;指定行格式3&#xff09;DYNAMIC 格式的组成3.数据区存储真实数据方式4.行的额外(管理)信息区5.头信息区域1&#xff09;删除一行记录时在InnoDB内部执行的操作6.Nu…

Rust系统编程实战:驾驭内存安全、无畏并发与WASM跨平台开发

简介本文深入探讨Rust在系统编程领域的核心实战应用&#xff0c;通过代码示例解析其所有权机制如何保障内存安全&#xff0c;如何利用 fearless concurrency 构建高性能并发应用&#xff0c;并实践如何将Rust代码编译为WebAssembly&#xff08;WASM&#xff09;以突破性能瓶颈。…

JavaScript 基础入门:从概念解析到流程控制

文章目录1. JavaScript 核心认知1.1 浏览器与 JavaScript 的关系1.2 JavaScript 的三大核心组成1.3 JavaScript 引入1.3.1 内联脚本&#xff08;事件属性绑定&#xff09;1.3.2 内部脚本&#xff08;<script> 标签嵌入&#xff09;1.3.3 外部脚本&#xff08;独立 .js 文…

WebSocket简单了解

WebSocket 是一种计算机网络通信协议&#xff0c;它在客户端和服务器之间建立一个持久的、双向的通信通道。与传统的 HTTP 请求-响应模型不同&#xff0c;WebSocket 允许数据在客户端和服务器之间实时双向传输&#xff0c;因此非常适合需要即时交互的应用&#xff0c;如实时聊天…