RSA加密算法及其与SpringMVC集成
如有不足,敬请各位提出批评,定会改正。THX!
本文介绍的是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、前台请求服务器的公钥,传输到前台,因为公钥是公开的,使用公钥在前台加密用户登录注册或者其他保密的信息,将公钥加密的密文传输到服务器。服务器通过与公钥对应的私钥,解密数据库的密文和传输过来的密文,将解密后的字符相比较,再将确认信息返回到前台,进行下一步的操作。
RSA加密算法及其与SpringMVC集成的更多相关文章
- SpringMVC集成RSA加密算法
技术交流群: 233513714 本文介绍的是RSA加密算法+Spring Security在SpringMVC中的集成使用. Spring Security是什么? 引用: Spring Secur ...
- .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 ...
随机推荐
- EF中加载实体的方式
EF中的查询执行时机:1. foreach进行枚举2. ToArray.ToList.ToDictionary3. Linq的一些操作,如First.Any4. DbSet上的Load操作.DbEnt ...
- 使用hbase的api创建表时出现的异常
/usr/lib/jvm/java-7-openjdk-amd64/bin/java -Didea.launcher.port=7538 -Didea.launcher.bin.path=/usr/l ...
- (转).net程序员转战android第三篇---登录模块之静态登录
这一篇我将分2个部分记录登录界面,第一部分是静态登录, 这部分将如何从界面布局.控件使用.文件关系.数据验证.登陆实现等5小块记录. 第二部分是动态登录,这块会基于上面的4小块,在数据验证不是静态数据 ...
- Access restriction: The type * is not accessible due to restrict,报错问题
解决方案1: Eclipse 默认把这些受访问限制的API设成了ERROR. Windows -> Preferences -> Java -> Compiler -> Er ...
- Unable to open log device '/dev/log/main': No such file or directory
在我们使用真机进行Android应用调试时,无法获得调试信息,错误提示如下:Unable to open log device '/dev/log/main': No such file or dir ...
- deflate树与deflate编码
关于deflate树,能搜到的资料非常少,这个概念来自gzip的压缩算法,是由huffman树转变过来的.这里简单记录下deflate树的生成过程以及deflate编码. 假设以5 8 9 10 14 ...
- 【译】神经网络与深度学习 Ch1-Section0
用神经网络识别手写数字 人类的视觉系统是是大自然的奇迹.考虑下面手写数字序列: 大多数人能够轻易地是识别出是504192.在我们大脑的每个半球都有一个基础的皮质,这就是我们熟知的V1区,它包含了14亿 ...
- NSString 去掉前后空格或回车符
NSString *string = @" spaces in front and at the end "; NSString *trimmedString = [string ...
- jsp跳转到servlet
web.xml中url-pattern的值必须和相关联的jsp页面form中的action的值一样,才会从jsp页面跳转到servlet.
- TOMCAT之性能跟踪入门
先扫清前面的障碍,再慢慢进入核心 转一下网上的我关心的话题,实施起来 ~~~ 使用Nginx作为反向代理时,Tomcat的日志记录的客户端IP就不在是真实的客户端IP,而是Nginx代理的IP.要解决 ...