SpringMVC集成RSA加密算法
技术交流群: 233513714
本文介绍的是RSA加密算法+Spring Security在SpringMVC中的集成使用。
Spring Security是什么?
引用:
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
Spring Security以前叫做acegi,是后来才成为Spring的一个子项目,也是目前最为流行的一个安全权限管理框架,它与Spring紧密结合在一起。
Spring Security关注的重点是在企业应用安全层为您提供服务,你将发现业务问题领域存在着各式各样的需求。银行系统跟电子商务应用就有很大的不同。电子商务系统与企业销售自动化工具又有很大不同。这些客户化需求让应用安全显得有趣,富有挑战性而且物有所值。Spring Security为基于J2EE的企业应用软件提供了一套全面的安全解决方案。
学习Spring Security的网址http://www.iteye.com/blogs/subjects/spingsecurity3inside。
Spring-Security 自带的加密算法有
- bcrypt
- plaintext
- sha
- sha-256
- md5
- md4
- {sha}
- {ssha}
由于md5加密算法,使用较为普遍,但是可以通过碰撞的方式破解,不采用。
RSA是什么?
同RSA(Ron Rivest,Adi Shamir,Len Adleman三位天才的名字)一样,ECC(Elliptic Curves Cryptography,椭圆曲线密码编码学)也属于公开密钥算法。但是ECC算法在jdk1.5后加入支持,目前仅仅只能完成密钥的生成与解析。
RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。今天只有短的RSA钥匙才可能被强力方式解破。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。但在分布式计算和量子计算机理论日趋成熟的今天,RSA加密安全性受到了挑战。RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
RSA密钥长度随着保密级别提高,增加很快。下表列出了对同一安全级别所对应的密钥长度。
保密级别
|
对称密钥长度(bit)
|
RSA密钥长度(bit)
|
ECC密钥长度(bit)
|
保密年限
|
80
|
80
|
1024
|
160
|
2010
|
112
|
112
|
2048
|
224
|
2030
|
128
|
128
|
3072
|
256
|
2040
|
192
|
192
|
7680
|
384
|
2080
|
256
|
256
|
15360
|
512
|
2120
|
如何实现的RSA+Spring Security 在Spring MVC中的实现,直接上web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:web="http://java.sun.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" metadata-complete="false" version="2.5">
<!--配置上下文参数,指定spring配置文件的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/applicationContext-*.xml</param-value>
</context-param>
<!--Spring Security 过滤器-->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--Spring 字符集过滤器 -->
<!--包含设置两个参数encoding和forceEncoding-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>excludeSuffixs</param-name>
<param-value>js,css,jpg,gif</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>com.user.sec.MyHttpSessionEventPublisher</listener-class>
</listener>
<!-- <listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener> -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>WEB-INF/classes/properties/log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>60000</param-value>
</context-param>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/applicationContext-springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<servlet-name>springmvc</servlet-name>
</filter-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<error-page>
<error-code>500</error-code>
<location>/500.html</location>
</error-page>
</web-app>
applicationContext-security.xml
Spring Security采用就近原则,有多个约束时,从上至下只要找到第一条满足就返回,因此因该将最严格的约束放在最前面,而将最宽松的约束放在最后面.auto-config属性可以让spring security为我们自动配置几种常用的权限控制机制,包括form,anonymous, rememberMe等。当然你也可以手工配置。例如:<http auto-config="true">
对于拦截pattern的设置,具体如下:
/ 所有带/的请求
/* 代表这个域下面的请求 例如:/user/xxx 这种会被拦截 但是不会拦截 /user/xxx/xxx
/** 代表跨域请求 例如:/user/xxx 和 /user/xxx/xxx都会被拦截
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd"> <global-method-security secured-annotations="enabled" />
<!--配置不过滤的资源,包括登陆请求,静态资源访问,注册页面,获取登陆注册验证码,当然也包括此篇文章所涉及从后台获取的公钥接口-->
<http pattern="/resources/**" security="none" />
<http pattern="/login.html" security="none" />
<http pattern="/register.html" security="none" />
<http pattern="/admin/user/getPairKey" security="none"
<http use-expressions="true" auto-config="true">
<!--允许登录用户操作 -->
<intercept-url pattern="/pages/**" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
<!--所有用户均可使用 -->
<!-- <intercept-url pattern="/**" access="permitAll" /> -->
<!-- 允许匿名用户访问 -->
<!-- <intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY" /> -->
<!-- <intercept-url pattern="/" access="ROLE_ANONYMOUS" /> -->
<!-- 验证失败页面 -->
<form-login login-page="/login.html"
authentication-failure-url="/login.html?error=true"
login-processing-url="/j_spring_security_check" default-target-url="/index.html"
always-use-default-target="true" />
<!-- 注销页面 -->
<logout logout-success-url="/login.html" />
<!-- 记住登陆 -->
<remember-me key="mpbuser" user-service-ref="userDetailService" />
<session-management invalid-session-url="/login.html"
session-authentication-error-url="/login.html">
<concurrency-control max-sessions="100"
error-if-maximum-exceeded="false" expired-url="/login.html" />
</session-management> <custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="myDefineFilter" />
<!-- 验证权限不足处理类 -->
<access-denied-handler ref="accessDeniedHandler" />
<http-basic />
</http> <beans:bean id="encoder"
class="org.springframework.security.crypto.password.StandardPasswordEncoder" />
<beans:bean id="RSAEncoder"
class="com.common.component.util.RSAPasswordEncoder" />
<authentication-manager alias="authenticationManager"
erase-credentials="false">
<authentication-provider user-service-ref="userDetailService">
<password-encoder ref="RSAEncoder" />
</authentication-provider>
<!--自定义Provider -->
<!-- <authentication-provider ref="myAuthenticationProvider"> </authentication-provider> -->
</authentication-manager>
<beans:bean id="myDefineFilter"
class="com.user.sec.MyFilterSecurityInterceptor">
<beans:property name="authenticationManager" ref="authenticationManager" /> <!-- <beans:property name="accessDecisionManager" ref="accessDecisionManager"
/> --> <beans:property name="securityMetadataSource" ref="databaseDefinitionSource" /> <beans:property name="accessDecisionManager" ref="myAccessDecisionManager" /> </beans:bean> <!-- <beans:bean id="myAuthenticationProvider" class="crowdfunding.user.sec.MyAuthenticationProvider"/> -->
<beans:bean id="databaseDefinitionSource"
class="com.user.sec.DefinitionSourceFactoryBean">
<beans:constructor-arg ref="resourceDetailService" />
<!-- <beans:constructor-arg ref="userDetailService" /> -->
</beans:bean> <beans:bean id="myAccessDecisionManager"
class="com.user.sec.MyAccessDecisionManager">
</beans:bean> <beans:bean id="accessDeniedHandler" class="com.user.sec.MyAccessDeniedHandler" /> </beans:beans>
RSAPasswordEncoder.Java
package com.common.component.util; import java.net.URLDecoder; import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.encoding.PasswordEncoder; import Decoder.BASE64Decoder;
import Decoder.BASE64Encoder;
import com.common.component.util.MpbSecureRSAUtil; /*******************************************************
* Description:自定义RSA处理类
* 如需增加Spring Security 另外的加密方式,重新定义此类<br/>
********************************************************/
public class RSAPasswordEncoder implements PasswordEncoder { /*****************************************
* Description:明文加密 <br/>
* @return
* @param rawPass
* 密码
******************************************/
public String encodePassword(String rawPass, Object salt) { String encoder = "";
try {
encoder = MpbSecureRSAUtil.decryptString(rawPass);
} catch (Exception e) { e.printStackTrace();
}
return encoder;
} /*****************************************
* Description:验证密码是否有效主要是此方法的使用<br/>
*
* @return boolean
******************************************/
public boolean isPasswordValid(String encPass, String rawPass, Object salt) { if ( !MpbStringUtil.isNotBlank(encPass) || encPass.length() == 0) {
return false;
}
String decPsw = MpbSecureRSAUtil.decryptString(encPass);
String inpdecPsw = MpbSecureRSAUtil.decryptStringByJs(rawPass);
try {
decPsw = URLDecoder.decode(decPsw, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
return false;
}
return inpdecPsw.equals(decPsw);
} /*****************************************
* Description:私钥解密 <br/>
*
* @return
******************************************/
public String decryptPassword(String rawPass, Object salt) { String encoder = "";
try {
encoder = MpbSecureRSAUtil.decryptString(rawPass);
} catch (Exception e) { e.printStackTrace();
}
return encoder;
} /*****************************************
* Description:Base64解密 <br/>
* @param key
* @return
* @throws Exception
******************************************/
public static byte[] decoderBase64(String key) throws Exception {
return (new BASE64Decoder()).decodeBuffer(key);
} /*****************************************
* Description:Base64加密 <br/>
*
* @param key
* @return
* @throws Exception
******************************************/
public static String encoderBase64(byte[] key) throws Exception {
return (new BASE64Encoder()).encodeBuffer(key);
} }
login.html
<script type="text/javascript" src="resources/js/RSA/security.js"></script>
function mysubmit() {
if ($("input[name='_spring_security_remember_me']").attr("checked") == "checked") {
//如果记住用户名和密码框被选中则执行remenber()方法
remember();
}else{
//如果未选中则清空cookie
$.mpbSetCookie("EBS_ISCHECKED", "");
}
//从后台获取公钥并加密,将加密后的密文传输到服务器处理
$.mpbPost(
"/admin/user/getPairKey",
{
"_method" : "GET"
},
function(data) { var modulus = data['modul'];
var exponent = data['exponent'];
var key = RSAUtils.getKeyPair(exponent, '', modulus);
var pwd = $("#psw").val();
pwd = encodeURIComponent(pwd);
pwd = RSAUtils.encryptedString(key, pwd);
//$("#psw").attr("value",pwd);
$("input[name='j_password']").val(pwd);
$("#myform").submit();
}); }
Controler.Java
@ResponseBody
@RequestMapping(value = "/getPairKey", method = RequestMethod.GET)
public Map<?,?> getKey() throws Exception {
RSAPublicKey publicKey = MpbSecureRSAUtil.getDefaultPublicKey(); Map<String, String> key = new HashMap<String,String>(); key.put("modul",
new String(Hex.encodeHex(publicKey.getModulus().toByteArray())));
key.put("exponent",
new String(Hex.encodeHex(publicKey.getPublicExponent()
.toByteArray()))); return key;
}
文件地址:
http://files.cnblogs.com/files/Sonet-life/security.js
http://files.cnblogs.com/files/Sonet-life/MpbSecureRSAUtil.rar
整个加密的思路:
1、项目在启动时就检查是否生成密钥对文件,没有就强制生成新的,记住利用RSA注册的用户在数据库保存的是加密后的密文,RSA密钥对文件要保证一致性,如果密钥对文件生成了新的,而且你没备份之前的密钥对文件,将会造成不可挽回的后果。最好的方法,通过对MpbSecureRSAUtil中密钥对文件的生成路径设置成硬盘下的,不要放到Tomcat服务器中,否则每次你删除项目的时候,或者重新部署都会造成密钥对文件的重新生成。或者每次都用旧的替换新生成的,保持可用性。
2、前台请求服务器的公钥,传输到前台,因为公钥是公开的,使用公钥在前台加密用户登录注册或者其他保密的信息,将公钥加密的密文传输到服务器。服务器通过与公钥对应的私钥,解密数据库的密文和传输过来的密文,将解密后的字符相比较,再将确认信息返回到前台,进行下一步的操作。
SpringMVC集成RSA加密算法的更多相关文章
- RSA加密算法及其与SpringMVC集成
如有不足,敬请各位提出批评,定会改正.THX! 本文介绍的是RSA加密算法+Spring Security在SpringMVC中的集成使用. Spring Security是什么? 引用: Sprin ...
- .net(c#)版RSA加密算法,拿走不谢
今天有同学对接一个支付平台,涉及到RSA的签名和验签.由于对方是java的sdk,翻成c#语言时,搞了半天也没搞定.网上搜的东西都是各种copy还不解决问题. 碰巧,我之前对接过连连银通的网银支付和代 ...
- RSA加密算法的简单案例
RSA加密算法是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击. 那关于RSA加密算法有哪些应用呢?以下举一个数据库身份验证的案例. 在使用数据集进行身份认证时,密码存在数据 ...
- RSA加密算法的java实现
package rsa; import java.security.*;import java.security.interfaces.*;import javax.crypto.*; public ...
- 用实例讲解RSA加密算法(精)
RSA是第一个比较完善的公开密钥算法,它既能用于加密,也能用于数字签名.RSA以它的三个发明者Ron Rivest, Adi Shamir, Leonard Adleman的名字首字母命名,这个算法经 ...
- 关于RSA加密算法的长度限制问题
RSA是常用的非对称加密算法.近来有学生在项目中使用System.Security类库中的RSA加密算法时,出现了“不正确的长度”,这实际上是因为待加密的数据超长所致..net Framework中提 ...
- RSA加密算法的加密与解密
转发原文链接:RSA加密算法加密与解密过程解析 1.加密算法概述 加密算法根据内容是否可以还原分为可逆加密和非可逆加密. 可逆加密根据其加密解密是否使用的同一个密钥而可以分为对称加密和非对称加密. 所 ...
- 【python网络编程】使用rsa加密算法模块模拟登录新浪微博
一.基础知识 http://blog.csdn.net/pi9nc/article/details/9734437 二.模拟登录 因为上学期参加了一个大数据比赛,需要抓取数据,所以就想着写个爬虫抓取新 ...
- 轻松学习RSA加密算法原理
转自:http://blog.csdn.net/sunmenggmail/article/details/11994013 http://blog.csdn.net/q376420785/articl ...
随机推荐
- Struts2_总结
还未学习的内容,如果到时候要用到,再去学.1.Lamda 表达式(很复杂,很少用)2.验证框架(默认验证方法 validation.方法开始前验证.开始后验证)3.UI标签(用的不多)4.类型转换中的 ...
- Build 2017 | 今儿来说说火得不行的认知服务吧(内附微软开发者大会在线峰会报名地址)
Everybody,新一期的 Build 2017 大会新技术详谈又来了,今天小编给大家带来了一个既智能又有趣的技术,你一定喜欢!不卖关子了,直奔我们本期的主题: [只需几行代码,就能让任何应用更智能 ...
- python+pywinauto之PC端自动化一
所需软件安装: 1.下载 pywinauto 安装参考: https://jingyan.baidu.com/article/414eccf6a1a3906b421f0a59.html 下载地址: h ...
- 【2017-07-04】Qt信号与槽深入理解之一:信号与槽的连接方式
今天是个好日子,嗯. 信号槽机制是Qt的特色功能之一,类似于windows中的消息机制,在不同的类对象间传递消息时我们经常使用信号槽机制,然而很多时候都没有去关注connect()函数到底有几种重载的 ...
- python图形库(1)
python有很好图形库cv2(包含很多图形处理的算法),pylab(绘图工具模块) 这两个“模块”是肯定要配置的. 安装这两个模块可用了我不少时间. pylab它不是一个包,而是 numpy, sc ...
- python 面向对象(三)--继承和多态
在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超类(Base class.Supe ...
- 用到UdpClient的一点经验
Thread.Abort对UdpClient.Receive阻塞的线程无效 http://computer-programming-forum.com/4-csharp/184f9d4ee63704f ...
- Spring转换编码utf-8方式
方式一:修改Spring配置文件(建议使用) <mvc:annotation-driven> <mvc:message-converters register-defaults=&q ...
- 第16章 STM32中断应用概览—零死角玩转STM32-F429系列
第16章 STM32中断应用概览 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fi ...
- BeanNameAware接口和BeanFactoryAware接口(转)
迄今为止,所接触到的Bean都是“无知觉”的,就像黑客帝国中机械工厂里面“养殖”的人类,他们虽然能完成一定的功能,但是根本不知道自己在工厂(BeanFactory)中的代号(id) ...