润乾报表单独部署url安全之加解密函数
2017-05-30 11:30
309 查看
润乾报表与用户的系统集成,一般有两种方案。一是集成到用户系统中。二是将润乾报表单独部署到一个应用下。
两种方案各有利弊:第一种方案对于安全性等方面可以统一管理,但是报表本身如果数据量大并发大造成的压力会直接影响用户自己的系统。第二种方案在报表服务器承受压力过大数据量过大的时候,不会影响到用户本身的系统,也就是说就算报表服务器压力饱和进入等待状态,用户的系统也可以正常的使用,众所周知润乾报表的调用一般直接通过url的方式进行调用,那么第二种方案中的url就无法被用户系统所控制,造成了一定的安全隐患。
下面就介绍几种解决此类问题的方案之中的一种:对url进行加解密
案例场景:
通过用户系统访问一张报表时,当然会带着一些用户信息或是其他参数传递过来。如果这时这个url的明文被其他人记住,比如url拼参数username=zhangsan,这时李四记住了这个url并且与自己访问该资源的url进行对比发现传入参数为用户姓名拼音,由于采用的是第二种方案,用户系统并不能控制,这样就可以肆无忌惮的去查看其他人的信息,导致信息的泄漏。
解决思路:
这时我们可以采取对url中的明文进行加解密的操作,通过用户系统传递参数之前进行加密,然后传递到报表服务器端,在jsp中或者报表中进行解密。(下文介绍是在报表中解密)
实现方法:
一、首先确定加解密规则,这里使用的是AES加解密方法,密钥为16位英文,由于是说明将密钥定义死在相应类中。
二、通过测试类将username=zhangsan加密为:
880CB3013AB0D0F3A91B1C36B323F6E40294D3BE6EEFAA38135690CA3DCC61A2模拟用户系统传递参数到报表服务器的url为:
http://127.0.0.1:6001/demo/reportJsp/showReport.jsp?aes=880CB3013AB0D0F3A91B1C36B323F6E40294D3BE6EEFAA38135690CA3DCC61A2&raq=demo.raq
三、编写AES加解密的自定义函数,接受参数时只用到解密函数,加密函数是在报表中超链接等位置再次使用时可以调用加密函数。
1、实现AES加解密的类
public
class AES {
/**
* 加密
*
* @param content 需要加密的内容
* @param password 加密密码
* @return
*/
public static byte[] encrypt(String content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFo
4000
rmat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(byteContent);
return result; // 加密
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
/**解密
* @param content 待解密内容
* @param password 解密密钥
* @return
*/
public static byte[] decrypt(byte[] content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(content);
return result; // 加密
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
/**将二进制转换成16进制
* @param buf
* @return
*/
public static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/**将16进制转换为二进制
* @param hexStr
* @return
*/
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1)
return null;
byte[] result = new byte[hexStr.length()/2];
for (int i = 0;i< hexStr.length()/2; i++) {
int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
2、润乾自定义加解密函数中调用AES类
加密自定义函数:
//判断参数个数
if (this.param == null || this.param.getSubSize() !=0) {
MessageManager mm = EngineMessage.get();
throw new ReportError("encrypt:" + mm.getMessage("function.missingParam"));
}
//取得第一个参数,默认为表达式,需要把该表达式算出来,结果才是函数的参数值
Expression param1=(Expression)this. param.getLeafExpression();
if (param1 == null) { //判断参数是否为空
MessageManager mm = EngineMessage.get();
throw new ReportError("encrypt:" + mm.getMessage("function.invalidParam"));
}
//算出第一个参数值
Object result1 = Variant2.getValue(param1.calculate(ctx), false);
//判断第一个参数值是否为空
if (result1 == null) {
return null;
}
//判断第一个参数值的数据类型
if (! (result1 instanceof String)) {
MessageManager mm = EngineMessage.get();
throw new ReportError("encrypt:" + mm.getMessage("function.paramTypeError"));
}
// 算出第一个参数值
Object result2 = Variant2.getValue(param1.calculate(ctx),false);
// 判断第一个参数值是否为空
if (result2 == null) {
return null;
}
AES aes = new AES();
byte[] value = aes.encrypt(result2.toString(),"aaaaaaaaaaaaaaaa");
String encryptResultStr = aes.parseByte2HexStr(value);
return encryptResultStr;
解密自定义函数:
//判断参数个数
if (this.param == null || this.param.getSubSize() !=0) {
MessageManager mm = EngineMessage.get();
throw new ReportError("encrypt:" + mm.getMessage("function.missingParam"));
}
//取得第一个参数,默认为表达式,需要把该表达式算出来,结果才是函数的参数值
Expression param1=(Expression)this. param.getLeafExpression();
if (param1 == null) { //判断参数是否为空
MessageManager mm = EngineMessage.get();
throw new ReportError("encrypt:" + mm.getMessage("function.invalidParam"));
}
//算出第一个参数值
Object result1 = Variant2.getValue(param1.calculate(ctx), false);
//判断第一个参数值是否为空
if (result1 == null) {
return null;
}
//判断第一个参数值的数据类型
if (! (result1 instanceof String)) {
MessageManager mm = EngineMessage.get();
throw new ReportError("encrypt:" + mm.getMessage("function.paramTypeError"));
}
// 算出第一个参数值
Object result2 = Variant2.getValue(param1.calculate(ctx),false);
// 判断第一个参数值是否为空
if (result2 == null) {
return null;
}
AES aes = new AES();
byte[] decryptFrom = aes.parseHexStr2Byte(result2.toString());
byte[] decryptResult = aes.decrypt(decryptFrom,"aaaaaaaaaaaaaaaa");
return new String(decryptResult);
四、 自定义函数注册
1,将编译后的class文件复制到
\report5\web\webapps\demo\WEB-INF\classes
2,在
\report5\web\webapps\demo\WEB-INF\classes\config\customFunctions.properties 文件加入以下内容.
encode=0,api.MyEncode
decode=0,api.MyDecode
3,如果\WEB-INF\classes目前下没有config目录,则可以自己创建.
如果已经存在,在该目录下执行上述步骤2.
重新启动设计器服务器。
在设计器中测试内容:
=encode(“ceshi”);
=decode(“555DF8AB73DAB1FF191A2B977430E02B”);
出现结果为正确.
五、报表中设定参数aes接受url中传递过来的值,通过动态参数调用解密函数将真实值取到进行报表中的运算。
两种方案各有利弊:第一种方案对于安全性等方面可以统一管理,但是报表本身如果数据量大并发大造成的压力会直接影响用户自己的系统。第二种方案在报表服务器承受压力过大数据量过大的时候,不会影响到用户本身的系统,也就是说就算报表服务器压力饱和进入等待状态,用户的系统也可以正常的使用,众所周知润乾报表的调用一般直接通过url的方式进行调用,那么第二种方案中的url就无法被用户系统所控制,造成了一定的安全隐患。
下面就介绍几种解决此类问题的方案之中的一种:对url进行加解密
案例场景:
通过用户系统访问一张报表时,当然会带着一些用户信息或是其他参数传递过来。如果这时这个url的明文被其他人记住,比如url拼参数username=zhangsan,这时李四记住了这个url并且与自己访问该资源的url进行对比发现传入参数为用户姓名拼音,由于采用的是第二种方案,用户系统并不能控制,这样就可以肆无忌惮的去查看其他人的信息,导致信息的泄漏。
解决思路:
这时我们可以采取对url中的明文进行加解密的操作,通过用户系统传递参数之前进行加密,然后传递到报表服务器端,在jsp中或者报表中进行解密。(下文介绍是在报表中解密)
实现方法:
一、首先确定加解密规则,这里使用的是AES加解密方法,密钥为16位英文,由于是说明将密钥定义死在相应类中。
二、通过测试类将username=zhangsan加密为:
880CB3013AB0D0F3A91B1C36B323F6E40294D3BE6EEFAA38135690CA3DCC61A2模拟用户系统传递参数到报表服务器的url为:
http://127.0.0.1:6001/demo/reportJsp/showReport.jsp?aes=880CB3013AB0D0F3A91B1C36B323F6E40294D3BE6EEFAA38135690CA3DCC61A2&raq=demo.raq
三、编写AES加解密的自定义函数,接受参数时只用到解密函数,加密函数是在报表中超链接等位置再次使用时可以调用加密函数。
1、实现AES加解密的类
public
class AES {
/**
* 加密
*
* @param content 需要加密的内容
* @param password 加密密码
* @return
*/
public static byte[] encrypt(String content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFo
4000
rmat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(byteContent);
return result; // 加密
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
/**解密
* @param content 待解密内容
* @param password 解密密钥
* @return
*/
public static byte[] decrypt(byte[] content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(content);
return result; // 加密
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
/**将二进制转换成16进制
* @param buf
* @return
*/
public static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/**将16进制转换为二进制
* @param hexStr
* @return
*/
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1)
return null;
byte[] result = new byte[hexStr.length()/2];
for (int i = 0;i< hexStr.length()/2; i++) {
int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
2、润乾自定义加解密函数中调用AES类
加密自定义函数:
//判断参数个数
if (this.param == null || this.param.getSubSize() !=0) {
MessageManager mm = EngineMessage.get();
throw new ReportError("encrypt:" + mm.getMessage("function.missingParam"));
}
//取得第一个参数,默认为表达式,需要把该表达式算出来,结果才是函数的参数值
Expression param1=(Expression)this. param.getLeafExpression();
if (param1 == null) { //判断参数是否为空
MessageManager mm = EngineMessage.get();
throw new ReportError("encrypt:" + mm.getMessage("function.invalidParam"));
}
//算出第一个参数值
Object result1 = Variant2.getValue(param1.calculate(ctx), false);
//判断第一个参数值是否为空
if (result1 == null) {
return null;
}
//判断第一个参数值的数据类型
if (! (result1 instanceof String)) {
MessageManager mm = EngineMessage.get();
throw new ReportError("encrypt:" + mm.getMessage("function.paramTypeError"));
}
// 算出第一个参数值
Object result2 = Variant2.getValue(param1.calculate(ctx),false);
// 判断第一个参数值是否为空
if (result2 == null) {
return null;
}
AES aes = new AES();
byte[] value = aes.encrypt(result2.toString(),"aaaaaaaaaaaaaaaa");
String encryptResultStr = aes.parseByte2HexStr(value);
return encryptResultStr;
解密自定义函数:
//判断参数个数
if (this.param == null || this.param.getSubSize() !=0) {
MessageManager mm = EngineMessage.get();
throw new ReportError("encrypt:" + mm.getMessage("function.missingParam"));
}
//取得第一个参数,默认为表达式,需要把该表达式算出来,结果才是函数的参数值
Expression param1=(Expression)this. param.getLeafExpression();
if (param1 == null) { //判断参数是否为空
MessageManager mm = EngineMessage.get();
throw new ReportError("encrypt:" + mm.getMessage("function.invalidParam"));
}
//算出第一个参数值
Object result1 = Variant2.getValue(param1.calculate(ctx), false);
//判断第一个参数值是否为空
if (result1 == null) {
return null;
}
//判断第一个参数值的数据类型
if (! (result1 instanceof String)) {
MessageManager mm = EngineMessage.get();
throw new ReportError("encrypt:" + mm.getMessage("function.paramTypeError"));
}
// 算出第一个参数值
Object result2 = Variant2.getValue(param1.calculate(ctx),false);
// 判断第一个参数值是否为空
if (result2 == null) {
return null;
}
AES aes = new AES();
byte[] decryptFrom = aes.parseHexStr2Byte(result2.toString());
byte[] decryptResult = aes.decrypt(decryptFrom,"aaaaaaaaaaaaaaaa");
return new String(decryptResult);
四、 自定义函数注册
1,将编译后的class文件复制到
\report5\web\webapps\demo\WEB-INF\classes
2,在
\report5\web\webapps\demo\WEB-INF\classes\config\customFunctions.properties 文件加入以下内容.
encode=0,api.MyEncode
decode=0,api.MyDecode
3,如果\WEB-INF\classes目前下没有config目录,则可以自己创建.
如果已经存在,在该目录下执行上述步骤2.
重新启动设计器服务器。
在设计器中测试内容:
=encode(“ceshi”);
=decode(“555DF8AB73DAB1FF191A2B977430E02B”);
出现结果为正确.
五、报表中设定参数aes接受url中传递过来的值,通过动态参数调用解密函数将真实值取到进行报表中的运算。
相关文章推荐
- 润乾报表单独部署url安全之加解密函数
- 润乾报表单独部署url安全之加解密
- 润乾报表单独部署(连接数据库)
- 报表单独部署时跨应用访问报表安全控制
- weblogic10下部署润乾报表demo
- 润乾报表在OC4J服务器下的部署方法
- 润乾报表部署中的常见问题–http 500 内部服务器错误解析
- weblogic10部署润乾报表中文乱码问题的解决
- 润乾报表V4.5在tomcat7下的部署
- 润乾报表整合到Tomcat服务器的部署过程
- weblogic部署润乾报表的授权问题
- 润乾报表怎样在tomcat7.0下部署demo应用(集算报表)
- 润乾V5部署url应用名为空applet无法打印解决方案
- 润乾报表在websphere8部署配置数据源报错 java.sql.SQLException: 调用中无效的参数DSRA0010E: SQL 状态 = null,错误代码 = 17,433 而失败
- 润乾报表分析1-通过url将参数传达给报表
- 润乾报表Weblogic集群配置__部署润乾应用
- 润乾集算报表的集算器数据集部署(I)
- 润乾报表V5.0 在weblogic服务器下的部署
- 润乾报表图形报表部署在Linux下出现乱码解决办法
- 润乾报表的最小化部署方式