【仅供内部供应商使用,不提供对外解答和培训】

Page tree

【仅供内部供应商使用,不提供对外解答和培训】

Skip to end of metadata
Go to start of metadata

一、特殊名词介绍

参数解密:特指在访问决策系统资源时,传递的参数为加密数据的场景。

二、常用接口说明

参数解密又分为以下几种细分场景:

1、请求的整个query被加密的情况 —— eg): 原始URL webroot/decision?p1=v1&p2=v2&pn=vn  ;    加密后URL webroot/decision?crypt=code1  其中code1 就是 p1=v1&p2=v2&pn=vn 加密的密文

2、请求的query参数名、参数值分别被加密或仅参数值被加密 —— eg): 原始URL webroot/decision?p1=v1&p2=v2&pn=vn  ; 加密后URL webroot/decision?p1=code1&p2=code2&pn=coden

3、参数通过请求的body/header加密传输


实现参数的解密主要依赖于请求的拦截。最主要的接口就是GlobalRequestFilterProvider 和 RequestParameterHandler。二者都可以在一定条件下实现请求参数的解密,但各有缺陷。

其中GlobalRequestFilterProvider接口,可通过篡改请求信息的手段来实现,参数的解密。但是该接口不支持热部署,每次更新、安装、注册授权 均需要重启服务器才能保障有效。

RequestParameterHandler接口,本身是通过在产品封装的参数读取API内部,进行替换从而实现参数的解密,也就是该接口只能用于通过产品标准API读取参数的场景。类似body和header中的加密场景并不一定能使用。


而根据参数加密的具体实现位置,场景又分为:前端加密后端加密两种。

通常后端加密主要用于安全性较高的场景,相对的对服务器的消耗就较大一些。而前端加密由于加密过程可被前端直接较低成本就模拟实现一般用于安全性要求略低,但是加密并发算力要求较高的场景,减小服务端开销。


加密的方案按照加密使用的算法又分为:不可逆加密(校验类)和可逆加密

常见的不可逆加密(校验类)本质并不是对请求的参数进行加密,而是通过某种私钥对请求的参数进行签名(常见的 MD5\SHA256)。参数读取时,利用私钥校验参数和签名是否匹配来确保参数的有效。这类方案的重点不在于加密参数值,防止别人知晓参数的具体值。而是强调请求参数的不可篡改或者说访问资源的有效授权甚至预防请求重放

不可逆加密伪代码示例
//场景:以固定密钥进行MD5参数签名为例。现有业务系统服务器SA,和决策平台FR。
//在浏览器B上,通过登录SA访问FR的报表X,对其中的参数p1和p2进行防篡改保护

//准备:SA和FR后台约定一个固定且复杂度安全的密钥SCT, 假设不存在人为泄露密钥的可能。

//SA服务端生成校验信息:
func( Map parameters )
//parameters是原始报表的url的参数表信息
String query = sort(parameters);
//sort方法表示,将参数表按照双方约定的某种排序方法进行排序得到一个固定的参数名与参数值的键值对字符串
String SIGN = MD5( query + SCT + timestamp + timeout ) + timestamp + timeout
//其中timestamp表示生成签名的时间戳,timeout表示签名的有效期

//浏览器B实际访问的URL 为 url?query&sign=SIGN

//FR服务器在处理需要校验参数的请求获取具体参数时,先校验签名信息
//获取请求中的签名对象SIGN{ md5,timestamp, timeout}
SIGN sign = getSign(req);
//判断是否超时
if( isTimeout( sign.timestamp, sign.timeout, crtTimestamp ) ){
	//超时,返回一个参数空值/或者抛出异常
	return StringUtils.EMPTY;
}
//比较md5值是否一致
//此时的parameters需要排除sign参数
String query = sort(parameters);
if( sign.md5 != MD5(query + SCT + sign.timestamp + sign.timeout) ){
	//签名不匹配,返回一个参数空值/或者抛出异常
	return StringUtils.EMPTY;
}
//返回获取到的具体参数值
return value;


常见的可逆加密相应的,是对参数信息本身进行加密。密文可以通过可逆手段还原出原来的明文信息。它即可保障在密钥安全的前提下,请求不被篡改;也可以保障参数值本身不被肉眼或简单算法逆向识别。这类方案的重点则是保护参数中涉及的涉敏信息,诸如密码、身份证号、手机号、邮箱等等信息不轻易泄露。常见的可逆加密主要有 3DES、AES、RSA、HMAC等算法。

可逆加密伪代码示例
//场景:以固定密钥进行AES参数加密为例。现有业务系统服务器SA,和决策平台FR。
//在浏览器B上,通过登录SA访问FR的报表X,对其中的参数p1和p2进行加密保护(仅加密参数值)

//准备:SA和FR后台约定一个固定且复杂度安全的密钥SCT, 假设不存在人为泄露密钥的可能。

//SA服务端生成加密信息:
func( Map parameters )
for( Entry entry : parameters ){
	entry.setValue( AES_E( entry.getValue(), SCT ) );
}
String query = toQuery(parameters);

//浏览器B最终访问 url?query

//FR服务器在处理需要校验参数的请求获取具体参数时,进行参数解密
//获取请求中的参数密文
String value = req.getParameter(name);
//解密密文
return AES_D( value, SCT );


GlobalRequestFilterProviderRequestParameterHandler在一定条件下都可以实现上面的两种场景。


在实践中,参数加密还存在一种特殊的变种,这类变种本身是通过将参数表用服务映射到一个随机的一次性ID上,让报表服务器利用ID来实现参数的实际获取。这类方案主要用于模板访问权限的变种授权(不让你用对应的参数来实现不允许你访问数据)和防重放攻击(ID由业务系统签发,可进行一次性的管理,防止重放)。方案的逻辑大致如下

可逆加密伪代码示例
场景:现有业务系统服务器SA,和决策平台FR。
在浏览器B上,通过登录SA,并向SA的服务器申请以p1=v1&p2=v2参数组合访问 FR的报表X

STEP1  B  通过URL_O 向SA申请 访问 X
STEP2  SA 接收到请求URL_O 后判断该用户是否有X报表的访问权限和对应的参数值权限,没有则终止
STEP3  如果有权限 SA 将参数组合 关联一个随机ID,有效期T。重定向到 FR的X报表的访问请求并携带ID
STEP4  FR 报表入口请求获取参数时,将ID 通过约定的请求 URL_P 将ID和密钥/或某种约定的TOKEN,发给SA 。
STEP5  SA确认请求时FR服务器发来时,通过ID找到对应的参数表,返回给报表服务器。(超时的参数会被自动移除,此时如果要防重放就删除该缓存),如果没有参数表则通知FR异常
STEP6  FR拿到参数后就可正常计算报表了。

这种方案的安全性理论上是这几类方案中最高的,该方案本身在用户浏览器上只传递了ID信息,完全没有参数的任何特征,不需要担心参数被别人抓取或泄露。但是这个方案从实践中看,也只能用于报表的访问入口请求。

三、开源案例

免责声明:所有文档中的开源示例,均为开发者自行开发并提供。仅用于参考和学习使用,开发者和官方均无义务对开源案例所涉及的所有成果进行教学和指导。若作为商用一切后果责任由使用者自行承担。

demo-parameter-decode【两种接口实现的基于MD5的密码防篡改代码】

  • No labels