一般我们在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两个包。 下面是具体的实现:
-
importjavax.mail.internet.MimeUtility;
-
publicclassBase64{
-
publicstaticbyte[]encode(byte[]b)throwsException{
-
ByteArrayOutputStreambaos=null;
-
OutputStreamb64os=null;
-
try{
-
baos=newByteArrayOutputStream();
-
b64os=MimeUtility.encode(baos,"base64");
-
b64os.write(b);
-
b64os.close();
-
returnbaos.toByteArray();
-
}catch(Exceptione){
-
thrownewException(e);
-
}finally{
-
try{
-
if(baos!=null){
-
baos.close();
-
baos=null;
-
}
-
}catch(Exceptione){
-
}
-
try{
-
if(b64os!=null){
-
b64os.close();
-
b64os=null;
-
}
-
}catch(Exceptione){
-
}
-
}
-
}
-
publicstaticbyte[]decode(byte[]b)throwsException{
-
ByteArrayInputStreambais=null;
-
InputStreamb64is=null;
-
try{
-
bais=newByteArrayInputStream(b);
-
b64is=MimeUtility.decode(bais,"base64");
-
byte[]tmp=newbyte[b.length];
-
intn=b64is.read(tmp);
-
byte[]res=newbyte[n];
-
System.arraycopy(tmp,0,res,0,n);
-
returnres;
-
}catch(Exceptione){
-
thrownewException(e);
-
}finally{
-
try{
-
if(bais!=null){
-
bais.close();
-
bais=null;
-
}
-
}catch(Exceptione){
-
}
-
try{
-
if(b64is!=null){
-
b64is.close();
-
b64is=null;
-
}
-
}catch(Exceptione){
-
}
-
}
-
}
-
}
四、加密解密工具类的实现
有了BASE64的工具类,下面的工作将变得简单了,编写我们的加密解密工具类吧:
-
importjava.io.DataOutputStream;
-
importjava.io.FileOutputStream;
-
importjava.security.*;
-
importjavax.crypto.*;
-
importjavax.crypto.spec.*;
-
importjava.util.*;
-
importorg.apache.commons.logging.Log;
-
importorg.apache.commons.logging.LogFactory;
-
publicclassSecurityHelper{
-
protectedfinalstaticLoglogger=LogFactory.getLog(SecurityHelper.class);
-
privatefinalstaticintITERATIONS=20;
-
publicstaticStringencrypt(Stringkey,StringplainText)throwsException{
-
StringencryptTxt="";
-
try{
-
byte[]salt=newbyte[8];
-
MessageDigestmd=MessageDigest.getInstance("MD5");
-
md.update(key.getBytes());
-
byte[]digest=md.digest();
-
for(inti=0;i<8;i++){
-
salt[i]=digest[i];
-
}
-
PBEKeySpecpbeKeySpec=newPBEKeySpec(key.toCharArray());
-
SecretKeyFactorykeyFactory=SecretKeyFactory
-
.getInstance("PBEWithMD5AndDES");
-
SecretKeyskey=keyFactory.generateSecret(pbeKeySpec);
-
PBEParameterSpecparamSpec=newPBEParameterSpec(salt,ITERATIONS);
-
Ciphercipher=Cipher.getInstance("PBEWithMD5AndDES");
-
cipher.init(Cipher.ENCRYPT_MODE,skey,paramSpec);
-
byte[]cipherText=cipher.doFinal(plainText.getBytes());
-
StringsaltString=newString(Base64.encode(salt));
-
StringciphertextString=newString(Base64.encode(cipherText));
-
returnsaltString+ciphertextString;
-
}catch(Exceptione){
-
thrownewException("EncryptTextError:"+e.getMessage(),e);
-
}
-
}
-
publicstaticStringdecrypt(Stringkey,StringencryptTxt)
-
throwsException{
-
intsaltLength=12;
-
try{
-
Stringsalt=encryptTxt.substring(0,saltLength);
-
Stringciphertext=encryptTxt.substring(saltLength,encryptTxt
-
.length());
-
byte[]saltarray=Base64.decode(salt.getBytes());
-
byte[]ciphertextArray=Base64.decode(ciphertext.getBytes());
-
PBEKeySpeckeySpec=newPBEKeySpec(key.toCharArray());
-
SecretKeyFactorykeyFactory=SecretKeyFactory
-
.getInstance("PBEWithMD5AndDES");
-
SecretKeyskey=keyFactory.generateSecret(keySpec);
-
PBEParameterSpecparamSpec=newPBEParameterSpec(saltarray,
-
ITERATIONS);
-
Ciphercipher=Cipher.getInstance("PBEWithMD5AndDES");
-
cipher.init(Cipher.DECRYPT_MODE,skey,paramSpec);
-
byte[]plaintextArray=cipher.doFinal(ciphertextArray);
-
returnnewString(plaintextArray);
-
}catch(Exceptione){
-
thrownewException(e);
-
}
-
}
注意上面加粗的三处地方:
private final static int ITERATIONS = 20;
上面的值越大,加密越深,一般例子都以"Java安全性编程指南”这本书中的例子的值为准,设成1000,我们在这边只需要20就够了,原因就是考虑到加解密的速度问题。
int saltLength = 12;
这是base64解码后的盐的长度,加密后再经BASE64编码后盐的长度为8,BASE64解码后盐的长度为12,至于为什么,这也是根据BASE64的原理得出的,具体可以看BASE64原理,网上很多,说得也都很简单。
PBEWithMD5AndDES
我们使用的是PBEWithMD5AndDES加密。
下面编写一个测试类
-
publicstaticvoidmain(String[]args){
-
StringencryptTxt="";
-
StringplainTxt="helloohmygod";
-
try{
-
System.out.println(plainTxt);
-
encryptTxt=encrypt("mypassword01",plainTxt);
-
plainTxt=decrypt("mypassword01",encryptTxt);
-
System.out.println(encryptTxt);
-
System.out.println(plainTxt);
-
}catch(Exceptione){
-
e.printStackTrace();
-
System.exit(-1);
-
}
-
}
-
}
五、工具类在struts action中的具体使用
-
MyTaskDTOtaskDTO=newMyTaskDTO();
-
TaskInstanceti=(TaskInstance)it.next();
-
taskDTO.setTaskName(ti.getName());
-
taskDTO.setTaskCreateDate(sd.format(ti.getCreate()));
-
taskDTO.setTaskDescr(ti.getDescription());
-
-
StringtaskId=String.valueOf(ti.getId());
-
StringtokenId=String.valueOf(ti.getToken().getId());
-
processImgName=PropertyUtil.getProperty(
-
Constants.BPM_PROCESS_PAYMENT_PROCESSIMAGE).toString()
-
+".jpg";
-
processDefId=String.valueOf(ti.getToken()
-
.getProcessInstance().getProcessDefinition().getId());
-
-
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页面的处理如下:
-
StringprocessImgPath=taskDTO.getProcessImageName();
-
StringprocessDefId=taskDTO.getProcessDefinitionId();
-
processImgPath=java.net.URLEncoder.encode(processImgPath,"UTF-8");
-
processDefId=java.net.URLEncoder.encode(processDefId,"UTF-8");
-
StringshowProcessImgUrl=request.getContextPath()+"/queryMyTask.do";
-
<ahref="<%=showProcessImgUrl%>?method=showProcessImg&processDefinitionId=<%=processDefId%>&processImgPath=<%=processImgPath%>"target="_blank"><u><spanclass="left_txt">查看当前进程</span></u></a>
七、在接受加密参数的action中对加密的值进行解密
我们假设我们的接受的action为: queryMyTask.do,它接受一系列的参数,基中,processDefId和processImgPath是加密的。
实现如下:
-
StringprocessImgFilePath="";
-
StringprocessDefinitionId=(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=mykeypassword=secretalgorithm=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-scanbase-package="jbpmweb"/>
-
<beanid="environmentVariablesConfiguration"
-
class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig"
-
p:algorithm="PBEWithMD5AndDES"p:passwordEnvName="APP_ENCRYPTION_PASSWORD"/>
-
-
-
-
<beanid="configurationEncryptor"class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor"
-
p:config-ref="environmentVariablesConfiguration"/>
-
<beanid="propertyConfigurer"
-
class="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer">
-
<constructor-argref="configurationEncryptor"/>
-
<propertyname="locations">
-
<list>
-
<value>classpath:xxx.properties</value>
-
</list>
-
</property>
-
</bean>
-
<!--
-
Configurerthatreplaces${...}placeholderswithvaluesfroma
-
propertiesfile
-
-->
-
<context:property-placeholderlocation="classpath:jbpmweb.properties"/>
-
<beanid="commonsConfigurationFactoryBean"class="xxx.xxx.CommonsConfigurationFactoryBean"
-
p:systemPropertiesModeName="SYSTEM_PROPERTIES_MODE_OVERRIDE"p:encryptor-ref="configurationEncryptor">
-
<constructor-arg>
-
<beanclass="org.apache.commons.configuration.PropertiesConfiguration">
-
<constructor-argvalue="xxx.properties"/>
-
</bean>
-
</constructor-arg>
-
</bean>
-
-
-
<beanid="propertiesConfiguration"factory-bean="&commonsConfigurationFactoryBean"
-
factory-method="getConfiguration"/>
分享到:
相关推荐
主要介绍了JSP页面传参出现中文乱码的解决方案,非常实用,需要的朋友可以参考下
JSP struts2 url传参中文乱码解决办法.docx
jsp url传参 , 可以传#等特殊字符的处理
jsp使用URL编码传递中文参数乱码问题
Jsp页面在URL中传递参数会出现乱码,本人想到两种方法解决,虽然不能保证100%解决,但值得学习
jsp传参 servlet接收中文乱码问题的解决方法.docx
是jsp的MD5加密包括JSP程序和JAVA程序
base64 jsp版本加密及调用
主要介绍了JSP struts2 url传参中文乱码解决办法的相关资料,需要的朋友可以参考下
前言 JSP 页面间传递参数是项目中经常需要的,这应该算是 web 基本功吧。试着将各种方式总结下来,需要时可以进行权衡利弊...<jsp page=next.jsp><jsp name=paramA value=A/></jsp> <jsp page=next.jsp><jsp:para
NULL 博文链接:https://1601844782.iteye.com/blog/2271821
Head First Servlet JSP 中文无加密 可以编辑,打印等最高权限 工 6 部分
jsp加密解密问题.rar url参数加密解决
NULL 博文链接:https://youzhibing.iteye.com/blog/2166047
1.传递参数: 代码如下: var pmt = ‘sensor=’+ encodeURI(encodeURI(sensor))... top.location.href = ‘jsp/print/diagnosticAnaPrint.jsp?’+pmt; 2.接收和解析参数 代码如下: //获取URL参数 function GetRequest()
jsp md5 加密算法 实现加密 1
在JSP中如何实现MD5加密
jsp页面传参乱码的解决方法 jsp页面js: encodeURIComponent要使用两次encodeURIComponent(encodeURIComponent(userAccount)); java:String userAccount = java.net.URLDecoder.decode(userAccount,”UTF-8″);/*...
SHA(Secure Hash Algorithm,安全散列算法),是一种不可逆的数据加密算法。现在已经成为工人的最安全的散列算法之以。