`

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两个包。 下面是具体的实现:

Java代码
  1. importjavax.mail.internet.MimeUtility;
  2. publicclassBase64{
  3. publicstaticbyte[]encode(byte[]b)throwsException{
  4. ByteArrayOutputStreambaos=null;
  5. OutputStreamb64os=null;
  6. try{
  7. baos=newByteArrayOutputStream();
  8. b64os=MimeUtility.encode(baos,"base64");
  9. b64os.write(b);
  10. b64os.close();
  11. returnbaos.toByteArray();
  12. }catch(Exceptione){
  13. thrownewException(e);
  14. }finally{
  15. try{
  16. if(baos!=null){
  17. baos.close();
  18. baos=null;
  19. }
  20. }catch(Exceptione){
  21. }
  22. try{
  23. if(b64os!=null){
  24. b64os.close();
  25. b64os=null;
  26. }
  27. }catch(Exceptione){
  28. }
  29. }
  30. }
  31. publicstaticbyte[]decode(byte[]b)throwsException{
  32. ByteArrayInputStreambais=null;
  33. InputStreamb64is=null;
  34. try{
  35. bais=newByteArrayInputStream(b);
  36. b64is=MimeUtility.decode(bais,"base64");
  37. byte[]tmp=newbyte[b.length];
  38. intn=b64is.read(tmp);
  39. byte[]res=newbyte[n];
  40. System.arraycopy(tmp,0,res,0,n);
  41. returnres;
  42. }catch(Exceptione){
  43. thrownewException(e);
  44. }finally{
  45. try{
  46. if(bais!=null){
  47. bais.close();
  48. bais=null;
  49. }
  50. }catch(Exceptione){
  51. }
  52. try{
  53. if(b64is!=null){
  54. b64is.close();
  55. b64is=null;
  56. }
  57. }catch(Exceptione){
  58. }
  59. }
  60. }
  61. }

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

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

Java代码
  1. importjava.io.DataOutputStream;
  2. importjava.io.FileOutputStream;
  3. importjava.security.*;
  4. importjavax.crypto.*;
  5. importjavax.crypto.spec.*;
  6. importjava.util.*;
  7. importorg.apache.commons.logging.Log;
  8. importorg.apache.commons.logging.LogFactory;
  9. publicclassSecurityHelper{
  10. protectedfinalstaticLoglogger=LogFactory.getLog(SecurityHelper.class);
  11. privatefinalstaticintITERATIONS=20;
  12. publicstaticStringencrypt(Stringkey,StringplainText)throwsException{
  13. StringencryptTxt="";
  14. try{
  15. byte[]salt=newbyte[8];
  16. MessageDigestmd=MessageDigest.getInstance("MD5");
  17. md.update(key.getBytes());
  18. byte[]digest=md.digest();
  19. for(inti=0;i<8;i++){
  20. salt[i]=digest[i];
  21. }
  22. PBEKeySpecpbeKeySpec=newPBEKeySpec(key.toCharArray());
  23. SecretKeyFactorykeyFactory=SecretKeyFactory
  24. .getInstance("PBEWithMD5AndDES");
  25. SecretKeyskey=keyFactory.generateSecret(pbeKeySpec);
  26. PBEParameterSpecparamSpec=newPBEParameterSpec(salt,ITERATIONS);
  27. Ciphercipher=Cipher.getInstance("PBEWithMD5AndDES");
  28. cipher.init(Cipher.ENCRYPT_MODE,skey,paramSpec);
  29. byte[]cipherText=cipher.doFinal(plainText.getBytes());
  30. StringsaltString=newString(Base64.encode(salt));
  31. StringciphertextString=newString(Base64.encode(cipherText));
  32. returnsaltString+ciphertextString;
  33. }catch(Exceptione){
  34. thrownewException("EncryptTextError:"+e.getMessage(),e);
  35. }
  36. }
  37. publicstaticStringdecrypt(Stringkey,StringencryptTxt)
  38. throwsException{
  39. intsaltLength=12;
  40. try{
  41. Stringsalt=encryptTxt.substring(0,saltLength);
  42. Stringciphertext=encryptTxt.substring(saltLength,encryptTxt
  43. .length());
  44. byte[]saltarray=Base64.decode(salt.getBytes());
  45. byte[]ciphertextArray=Base64.decode(ciphertext.getBytes());
  46. PBEKeySpeckeySpec=newPBEKeySpec(key.toCharArray());
  47. SecretKeyFactorykeyFactory=SecretKeyFactory
  48. .getInstance("PBEWithMD5AndDES");
  49. SecretKeyskey=keyFactory.generateSecret(keySpec);
  50. PBEParameterSpecparamSpec=newPBEParameterSpec(saltarray,
  51. ITERATIONS);
  52. Ciphercipher=Cipher.getInstance("PBEWithMD5AndDES");
  53. cipher.init(Cipher.DECRYPT_MODE,skey,paramSpec);
  54. byte[]plaintextArray=cipher.doFinal(ciphertextArray);
  55. returnnewString(plaintextArray);
  56. }catch(Exceptione){
  57. thrownewException(e);
  58. }
  59. }

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

private final static int ITERATIONS = 20;

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

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

PBEWithMD5AndDES

我们使用的是PBEWithMD5AndDES加密。

下面编写一个测试类

Java代码
  1. publicstaticvoidmain(String[]args){
  2. StringencryptTxt="";
  3. StringplainTxt="helloohmygod";
  4. try{
  5. System.out.println(plainTxt);
  6. encryptTxt=encrypt("mypassword01",plainTxt);
  7. plainTxt=decrypt("mypassword01",encryptTxt);
  8. System.out.println(encryptTxt);
  9. System.out.println(plainTxt);
  10. }catch(Exceptione){
  11. e.printStackTrace();
  12. System.exit(-1);
  13. }
  14. }
  15. }

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

Java代码
  1. MyTaskDTOtaskDTO=newMyTaskDTO();
  2. TaskInstanceti=(TaskInstance)it.next();
  3. taskDTO.setTaskName(ti.getName());
  4. taskDTO.setTaskCreateDate(sd.format(ti.getCreate()));
  5. taskDTO.setTaskDescr(ti.getDescription());
  6. /*noencrypteddata*/
  7. StringtaskId=String.valueOf(ti.getId());
  8. StringtokenId=String.valueOf(ti.getToken().getId());
  9. processImgName=PropertyUtil.getProperty(
  10. Constants.BPM_PROCESS_PAYMENT_PROCESSIMAGE).toString()
  11. +".jpg";
  12. processDefId=String.valueOf(ti.getToken()
  13. .getProcessInstance().getProcessDefinition().getId());
  14. /*encrypteddata*/
  15. taskId=EncryptUrlPara.encrypt(taskId);
  16. tokenId=EncryptUrlPara.encrypt(tokenId);
  17. processImgName=EncryptUrlPara.encrypt(processImgName);
  18. processDefId=EncryptUrlPara.encrypt(processDefId);
  19. taskDTO.setTaskId(taskId);
  20. taskDTO.setTokenId(tokenId);
  21. taskDTO.setProcessDefinitionId(processDefId);
  22. taskDTO.setProcessImageName(processImgName);

六、jsp页面中的encode

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

Jsp代码
  1. StringprocessImgPath=taskDTO.getProcessImageName();
  2. StringprocessDefId=taskDTO.getProcessDefinitionId();
  3. processImgPath=java.net.URLEncoder.encode(processImgPath,"UTF-8");
  4. processDefId=java.net.URLEncoder.encode(processDefId,"UTF-8");
  5. StringshowProcessImgUrl=request.getContextPath()+"/queryMyTask.do";
  6. <ahref="<%=showProcessImgUrl%>?method=showProcessImg&processDefinitionId=<%=processDefId%>&processImgPath=<%=processImgPath%>"target="_blank"><u><spanclass="left_txt">查看当前进程</span></u></a>

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

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

实现如下:

Java代码
  1. StringprocessImgFilePath="";
  2. StringprocessDefinitionId=(String)request.getParameter("processDefinitionId");
  3. processImgFilePath=(String)request.getParameter("processImgPath");
  4. processDefinitionId=EncryptUrlPara.decrypt(processDefinitionId);
  5. 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自动完成的),以下是这一步配置的详细内容:

Xml代码
  1. <context:component-scanbase-package="jbpmweb"/>
  2. <beanid="environmentVariablesConfiguration"
  3. class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig"
  4. p:algorithm="PBEWithMD5AndDES"p:passwordEnvName="APP_ENCRYPTION_PASSWORD"/>
  5. <!--
  6. Thewillbetheencryptorusedfordecryptingconfigurationvalues.
  7. -->
  8. <beanid="configurationEncryptor"class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor"
  9. p:config-ref="environmentVariablesConfiguration"/>
  10. <beanid="propertyConfigurer"
  11. class="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer">
  12. <constructor-argref="configurationEncryptor"/>
  13. <propertyname="locations">
  14. <list>
  15. <value>classpath:xxx.properties</value>
  16. </list>
  17. </property>
  18. </bean>
  19. <!--
  20. Configurerthatreplaces${...}placeholderswithvaluesfroma
  21. propertiesfile
  22. -->
  23. <context:property-placeholderlocation="classpath:jbpmweb.properties"/>
  24. <beanid="commonsConfigurationFactoryBean"class="xxx.xxx.CommonsConfigurationFactoryBean"
  25. p:systemPropertiesModeName="SYSTEM_PROPERTIES_MODE_OVERRIDE"p:encryptor-ref="configurationEncryptor">
  26. <constructor-arg>
  27. <beanclass="org.apache.commons.configuration.PropertiesConfiguration">
  28. <constructor-argvalue="xxx.properties"/>
  29. </bean>
  30. </constructor-arg>
  31. </bean>
  32. <beanid="propertiesConfiguration"factory-bean="&amp;commonsConfigurationFactoryBean"
  33. factory-method="getConfiguration"/>

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics