`
wangshiyang
  • 浏览: 69382 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

jsp url 参数加密传送的终极解决方案

 
阅读更多

一般我们在form提交时不要担心我们的参数会显示给用户看。

我们主要解决的是以get方式进行url参数传递的问题,如:

http://xxx.xxx.xxx.xxx/xxx/xxx.do?pId=101&imageName=processimage.jpg这样的url pId=101&imageName=processimage.jgp这样的参数如何进行加密。

我们采用:

java.net.URLEncoder.encode(Base64编码(加密字串), StringCode) 这样的方法来对url中的参数进行加密。

首先我们先说一下如何加密。

一、算法的选择:

对于像对url中的参数进行加密的过程,我不建议使用rsa或者是三重des这样的加密算法,主要原因在于性能和速度会受影响。

我建议大家使用对称加密如:DES或者是PBE算法。

我们在这边就使用PBEWithMD5AndDES来实现加密。

二、加密原理

对于一个纯文本,加密后它会变成一堆乱码,这堆乱码包括了许多非法字符,我们不希望把这些字符放入bean中,因此在加密完后,我们还要对加密结果进行base64编码。

PBE从字面上理解,它必须使用一个口令,我们不希望我们的加密过于复杂而影响页面跳转的速度,因此我们不采用口令+KEY的形式,我们这边的口令就是我们的KEY

因此:

我们的整个加密过程实现如下:

输入口令(KEY)--> 加密文本 --> 以base64对加密后的结果进行编码-->以java.net.URLEncoder.encode编码成浏览器可以识别的形式-->传输给接受的action

而解密过程如下:

接受的action得到参数-->以base64对结果进行解码-->得到纯加密文本-->解密-->得到解密后的值

三、BASE64

这边对于BASE64的原理不多说了,只说实现,目前网上有很多实现方式,有自己写的,有用sun.misc.*的,我们在这个例子里将使用javax.mail.internet.MimeUtility自带的base64编码工具。

需要引入activation.jar和mail.jar两个包。 下面是具体的实现:

import javax.mail.internet.MimeUtility;

public class Base64 {
public static byte[] encode(byte[] b) throws Exception {
ByteArrayOutputStream baos = null;
OutputStream b64os = null;
try {
baos = new ByteArrayOutputStream();
b64os = MimeUtility.encode(baos, "base64");
b64os.write(b);
b64os.close();
return baos.toByteArray();
} catch (Exception e) {
throw new Exception(e);
} finally {
try {
if (baos != null) {
baos.close();
baos = null;
}
} catch (Exception e) {
}
try {
if (b64os != null) {
b64os.close();
b64os = null;
}
} catch (Exception e) {
}
}
}

public static byte[] decode(byte[] b) throws Exception {
ByteArrayInputStream bais = null;
InputStream b64is = null;
try {
bais = new ByteArrayInputStream(b);
b64is = MimeUtility.decode(bais, "base64");
byte[] tmp = new byte[b.length];
int n = b64is.read(tmp);
byte[] res = new byte[n];
System.arraycopy(tmp, 0, res, 0, n);

return res;
} catch (Exception e) {
throw new Exception(e);
} finally {
try {
if (bais != null) {
bais.close();
bais = null;
}
} catch (Exception e) {
}
try {
if (b64is != null) {
b64is.close();
b64is = null;
}
} catch (Exception e) {
}
}
}
}

四、加密解密工具类的实现

有了BASE64的工具类,下面的工作将变得简单了,编写我们的加密解密工具类吧:

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;

import java.util.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SecurityHelper {
protected final static Log logger = LogFactory.getLog(SecurityHelper.class);
private final static int ITERATIONS = 20;

public static String encrypt(String key, String plainText) throws Exception {
String encryptTxt = "";
try {
byte[] salt = new byte[8];
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(key.getBytes());
byte[] digest = md.digest();
for (int i = 0; i < 8; i++) {
salt[i] = digest[i];
}
PBEKeySpec pbeKeySpec = new PBEKeySpec(key.toCharArray());
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance("PBEWithMD5AndDES");
SecretKey skey = keyFactory.generateSecret(pbeKeySpec);
PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATIONS);
Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
cipher.init(Cipher.ENCRYPT_MODE, skey, paramSpec);
byte[] cipherText = cipher.doFinal(plainText.getBytes());
String saltString = new String(Base64.encode(salt));
String ciphertextString = new String(Base64.encode(cipherText));
return saltString + ciphertextString;
} catch (Exception e) {
throw new Exception("Encrypt Text Error:" + e.getMessage(), e);
}
}

public static String decrypt(String key, String encryptTxt)
throws Exception {
int saltLength = 12;
try {
String salt = encryptTxt.substring(0, saltLength);
String ciphertext = encryptTxt.substring(saltLength, encryptTxt
.length());
byte[] saltarray = Base64.decode(salt.getBytes());
byte[] ciphertextArray = Base64.decode(ciphertext.getBytes());
PBEKeySpec keySpec = new PBEKeySpec(key.toCharArray());
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance("PBEWithMD5AndDES");
SecretKey skey = keyFactory.generateSecret(keySpec);
PBEParameterSpec paramSpec = new PBEParameterSpec(saltarray,
ITERATIONS);
Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
cipher.init(Cipher.DECRYPT_MODE, skey, paramSpec);
byte[] plaintextArray = cipher.doFinal(ciphertextArray);
return new String(plaintextArray);
} catch (Exception e) {
throw new Exception(e);
}
}

注意上面加粗的三处地方:

private final static int ITERATIONS = 20;

上面的值越大,加密越深,一般例子都以"Java安全性编程指南”这本书中的例子的值为准,设成1000,我们在这边只需要20就够了,原因就是考虑到加解密的速度问题。

int saltLength = 12;
这是base64解码后的盐的长度,加密后再经BASE64编码后盐的长度为8,BASE64解码后盐的长度为12,至于为什么,这也是根据BASE64的原理得出的,具体可以看BASE64原理,网上很多,说得也都很简单。

PBEWithMD5AndDES

我们使用的是PBEWithMD5AndDES加密。

下面编写一个测试类

public static void main(String[] args) {
String encryptTxt = "";
String plainTxt = "hello oh my god";
try {
System.out.println(plainTxt);
encryptTxt = encrypt("mypassword01", plainTxt);
plainTxt = decrypt("mypassword01", encryptTxt);
System.out.println(encryptTxt);
System.out.println(plainTxt);
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}

}

五、工具类在struts action中的具体使用

MyTaskDTO taskDTO = new MyTaskDTO();
TaskInstance ti = (TaskInstance) it.next();
taskDTO.setTaskName(ti.getName());
taskDTO.setTaskCreateDate(sd.format(ti.getCreate()));
taskDTO.setTaskDescr(ti.getDescription());
/* no encrypted data */
String taskId = String.valueOf(ti.getId());
String tokenId = String.valueOf(ti.getToken().getId());
processImgName = PropertyUtil.getProperty(
Constants.BPM_PROCESS_PAYMENT_PROCESSIMAGE).toString()
+ ".jpg";
processDefId = String.valueOf(ti.getToken()
.getProcessInstance().getProcessDefinition().getId());

/* encrypted data */
taskId = EncryptUrlPara.encrypt(taskId);
tokenId = EncryptUrlPara.encrypt(tokenId);
processImgName = EncryptUrlPara.encrypt(processImgName);
processDefId = EncryptUrlPara.encrypt(processDefId);

taskDTO.setTaskId(taskId);
taskDTO.setTokenId(tokenId);
taskDTO.setProcessDefinitionId(processDefId);
taskDTO.setProcessImageName(processImgName);

六、jsp页面中的encode

把上述这个bean放入request中,带到下一个jsp页面中后,在jsp页面的处理如下:

String processImgPath=taskDTO.getProcessImageName();
String processDefId=taskDTO.getProcessDefinitionId();
processImgPath=java.net.URLEncoder.encode(processImgPath,"UTF-8");
processDefId=java.net.URLEncoder.encode(processDefId,"UTF-8");
String showProcessImgUrl=request.getContextPath()+"/queryMyTask.do";

<a href="<%=showProcessImgUrl%>?method=showProcessImg&processDefinitionId=<%=processDefId%>&processImgPath=<%=processImgPath%>" target="_blank"><u><span class="left_txt">查看当前进程</span></u></a>

七、在接受加密参数的action中对加密的值进行解密

我们假设我们的接受的action为: queryMyTask.do,它接受一系列的参数,基中,processDefId和processImgPath是加密的。

实现如下:

String processImgFilePath = "";
String processDefinitionId = (String) request.getParameter("processDefinitionId");
processImgFilePath = (String) request.getParameter("processImgPath");

processDefinitionId = EncryptUrlPara.decrypt(processDefinitionId);
processImgFilePath = EncryptUrlPara.decrypt(processImgFilePath);

需要注意的是此处不需要再decode了。

八、key(口令)的存放

因为我们这边的key就是口令,是一个文本,我们将它存放在server端的properties中,当然,我们也是加密存放的。

我们使用spring+jasypt1.5(java simple encrypt包)。

设我们有一个properties文件,其中:

security.des.key=ENC(OlO0LqELUuLOVreCtDngHaNgMcZWUyUg)

这个就是我们在encrypt和decrypt方法中用到的key.

我们不希望这个key以明文的形式设在properties中,我们对这个key再进行一次加密用的同样也是PBEWithMD5AndDES,当然因为有了spring因为有了jasypt包,因此这个过程一切是自动的。

我们使用jasypt包下的bin中自带的encrypt.bat工具:

encrypt input=mykey password=secret algorithm=PBEWithMD5AndDES

该命令会输出一行乱码,把这行乱码复制到properties文件中,在外层加上ENC(),如:

生成: OlO0LqELUuLOVreCtDngHaNgMcZWUyUg

放入properties后需要转换成: ENC(OlO0LqELUuLOVreCtDngHaNgMcZWUyUg)

然后在工程布署的机器上需要设一个环境变理,如:

set APP_ENCRYPTION_PASSWORD=secret 此处的值必须和上面encrypt.bat命令行中的password=后的值一样。

(linux请用export APP_ENCRYPTION_PASSWORD=secret)

然后配置spring,使该properties在工程被app 容器load时,自动解密,这样我们在我们的方法中直接取到该KEY时就已经是明文了(解密过程是jasypt+spring自动完成的),以下是这一步配置的详细内容:

<context:component-scan base-package="jbpmweb" />
<bean id="environmentVariablesConfiguration"
class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig"
p:algorithm="PBEWithMD5AndDES" p:passwordEnvName="APP_ENCRYPTION_PASSWORD" />

<!--
The will be the encryptor used for decrypting configuration values.
-->

<bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor"
p:config-ref="environmentVariablesConfiguration" />

<bean id="propertyConfigurer"
class="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg ref="configurationEncryptor" />
<property name="locations">
<list>
<value>classpath:xxx.properties</value>
</list>
</property>
</bean>

<!--
Configurer that replaces ${...} placeholders with values from a
properties file
-->
<context:property-placeholder location="classpath:jbpmweb.properties" />

<bean id="commonsConfigurationFactoryBean" class="xxx.xxx.CommonsConfigurationFactoryBean"
p:systemPropertiesModeName="SYSTEM_PROPERTIES_MODE_OVERRIDE" p:encryptor-ref="configurationEncryptor">
<constructor-arg>
<bean class="org.apache.commons.configuration.PropertiesConfiguration">
<constructor-arg value="xxx.properties" />
</bean>
</constructor-arg>
</bean>


<bean id="propertiesConfiguration" factory-bean="&amp;commonsConfigurationFactoryBean"
factory-method="getConfiguration"/>

分享到:
评论

相关推荐

    JSP乱码 N种解决方案

    本文将深入探讨“JSP乱码”的多种解决方案,并提供实用的解决策略。 1. **理解字符编码的基本概念** - 字符编码是计算机对文字进行存储和处理的标准,常见的有ASCII、GBK、UTF-8等。 - JSP页面默认使用ISO-8859-1...

    JSP中文问题及一套整体解决方案

    讨论了JSP中出现中文问题的起源,并着重从编码角度解释了出现乱码的原因,最后给出了一套整体的中文问题解决方案.

    JSP乱码解决方案

    本文将深入探讨JSP乱码的原因及其解决方案,帮助开发者有效地处理这类问题。 ### 1. JSP乱码的成因 - **字符集设置不一致**:JSP文件、HTML页面、HTTP头、Servlet输出以及数据库存储等环节的字符集设置不一致,...

    jsp加密解密问题.rar

    "jsp加密解密问题.rar"这个压缩包文件很可能包含了关于如何在JSP中实现URL参数加密与解密的源代码示例。 URL参数加密的主要目的是防止敏感信息在传输过程中被窃取或篡改。这包括用户名、密码、交易详情等关键数据。...

    jsp中文乱码的解决方案

    本文将深入探讨JSP中文乱码的成因以及提供多种解决方案,帮助开发者有效地处理这类问题。 ### 1. 乱码的可能原因 1. **编码设置不一致**:JSP页面、HTTP请求、响应、数据库等环节的字符编码设置不统一,导致字符在...

    JSP中js传递和解析URL参数以及中文转码和解码问题

    1.传递参数: 代码如下: var pmt = ‘sensor=’+ encodeURI(encodeURI(sensor))+’&device=’+encodeURI(encodeURI(device))+’&instrument=’;...接收和解析参数 代码如下: //获取URL参数 function GetRequest()

    JSP 学生排课选课系统源码含解决方案文档.zip

    JSP 学生排课选课系统源码含解决方案文档.zip JSP 学生排课选课系统源码含解决方案文档.zip JSP 学生排课选课系统源码含解决方案文档.zip JSP 学生排课选课系统源码含解决方案文档.zip JSP 学生排课选课系统源码含...

    url传值到Action乱码解决方案

    URL传值到Action乱码解决方案 在Web应用程序中,URL传值到Action是一个常见的操作,但是当传递中文参数时,经常会出现乱码问题。今天,我们将讨论如何解决URL传值到Action乱码问题,特别是在Struts2框架中。 乱码...

    Jsp页面在URL中传递参数会出现乱码问题解决

    本文将详细介绍两种解决JSP页面URL参数乱码的方法,虽然不能保证100%有效,但它们是实践中常用且有效的解决方案。 **方法一:修改Tomcat配置** 1. 首先,我们需要进入Tomcat服务器的配置目录,通常是`$CATALINA_...

    JSP中js传递和解析URL参数以及中文转码和解码问题.docx

    本文将详细介绍如何在JSP页面中利用JavaScript进行URL参数的传递和解析,并解决中文字符的编码与解码问题。 #### 二、URL参数传递 在JSP中,通常使用JavaScript来动态构建URL并传递参数。以下是一个典型的例子: ...

    编辑JSP卡死解决方案

    ### 编辑JSP卡死解决方案 在使用MyEclipse进行Web开发时,尤其是在处理JSP文件中的`&lt;% %&gt;`部分时,开发者经常会遇到IDE(集成开发环境)卡顿甚至无响应的情况。这种情况严重影响了开发效率。本文将详细介绍如何解决...

    jsp乱码解决方案 本方案解决了jsp常见的乱码问题

    ### jsp乱码解决方案 #### 一、引言 在Web开发中,特别是使用Java Server Pages (JSP)进行开发时,字符编码问题是一个经常遇到的技术难题。如果处理不当,很容易导致网页显示乱码,影响用户体验及数据的正确性。...

    jspurl中中文参数的乱码解决.docx

    本文主要讨论的是JSP中URL中中文参数导致的乱码问题及其解决方案。 首先,让我们深入理解HTTP请求的基本原理。HTTP请求有两种主要的数据提交方式:GET和POST。在GET请求中,表单数据会被附加到URL后面作为查询参数...

    java和jsp编程常见到的异常解决方案

    这是关于java和jsp编程常见到的异常解决方案,是很关键的一个知识!

    url传递的参数值中包含&时,url自动截断问题的解决方法

    一、问题的引出 在做一个公告浏览功能时,只要通过url传递的某参数值中包含 & 或 ,就会出现问题–该变量的值...所以,解决方法出现了—在传送参数前, 将&全部替换为& eg: var url = ”page.jsp?para1=a&b“ 做如下

    jsp 动态转静态 URL重写

    动态URL通常包含有服务器端脚本语言(如jsp)的参数,而静态URL则更易于理解和优化。本篇文章将详细探讨“jsp动态转静态URL重写”的概念、重要性以及实现方法。 一、动态URL与静态URL的区别 1. 动态URL:动态URL...

    jsp url中文乱码四种解决方式

    get提交中文乱码 地址重写中文乱码 jsp url中文乱码四种解决方式

    base64 jsp版本加密及调用

    在本主题“base64 jsp版本加密及调用”中,我们将深入探讨如何在Java Server Pages (JSP)环境中使用Base64进行数据加密和解密,以及如何在实际应用中调用这些功能。 首先,Base64的原理是将每3个字节的数据(24位)...

    JSP调用EXE解决方案

    JSP调用EXE解决方案的汇总,经本人验证可行!

Global site tag (gtag.js) - Google Analytics