Open fred-ye opened 9 years ago
以前一直都有一个疑问,如果客户端在和服务器端进行通信时,如果在中途客户端发送给服务器端的数据被不法分子拦截到了,然后不法分子修改了我的请求数据,再发送给服务器。那岂不是很危险,有没有什么方式来避免这种情况。举个例子,假设我登录网上银行进行转账操作,我想向'Milo'转1000元,于是我的操作向Server端送的数据是{from:'Fred', to:'Milo', amount: 1000},假设有不法分子'Abhi'截取到了这个数据报,然后把它改成{from:'Fred', to:'Abhi', amount: 90000}。于是情况就糟高了,银行在完全不知情的情况下,把我的钱转出了90000给'Abhi'。接着各种纠纷便来了。如何解决这个问题呢?
我记得之前在做一个APP,我们会调用到腾讯微博的API, 在腾讯微博中有一个上传多张图片(记得不清楚)的API,是属于一个高级接口,在调用时,腾讯要求开发者将请求的参数字段名的升序进行排列,然后采用SHA1算法生成消息摘要,或者说进行签名,将签名数据附在URL后传过去。当时,自己还不是很理解为什么要这样,后来在实际项目中也碰到了采用这种方式,提高数据交互的安全性。在此记录一下。
还是回到最初的这个问题,我们可以采用如下思路,当A想要将数据传递给B时,在发送数据的同时,把对应的消息摘要也发送过去。当B接收到数据时,根据传过来的数据重新计算消息摘要,然后比对A传过来的消息摘要,如果二者一致,则认为当前请求的数据是安全的,然后进行相应的处理。消息摘要的生成可以采用多种算法,如HmacHash256, MD5,SHA1等。
具体做法如下:
{from:'Fred', to:'Milo', amount: 1000}
1000|Fred|Milo
ABCDEFGHIJK
6ffa87395f4679512163b502be3921db5b085fae05f46a7fe22f111b7dadd586
http://chinabank.com/tranfer
{from:'Fred', to:'Milo', amount: 1000, signature:'6ffa87395f4679512163b502be3921db5b085fae05f46a7fe22f111b7dadd586'}
signature
以下是一段采用HmacHash256实现消息验证码的的代码片断:
HmacHash256
String macKey = "ABCDEFGHIJK"; String macData = "the data string"; Mac mac = Mac.getInstance("HmacSHA256"); byte[] secretByte = macKey.getBytes("UTF-8"); byte[] dataBytes = macData.getBytes("UTF-8"); SecretKey secret = new SecretKeySpec(secretByte, "HmacSHA256"); mac.init(secret); byte[] doFinal = mac.doFinal(dataBytes); String result = ""; for (int i = 0; i < doFinal.length; i++) { result += Integer.toHexString( (0x000000ff & doFinal[i]) | 0xffffff00).substring(6); } System.out.println(result);
将byte数组转成String, 也可采用如下代码,其原理可以参看Java中byte与16进制字符串的互换原理:
public static String bytesToHexString(byte[] src) { StringBuilder stringBuilder = new StringBuilder(""); if (src == null || src.length <= 0) { return null; } for (int i = 0; i < src.length; i++) { int v = src[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); }
在我们的项目中采用了类似上面的思路做了一个安全的enhancement。不过和上面的思路有一些区别。我们不仅会把这个加密后的数据signature传给Server端,同时还会把当前时间timestamp传递过去。为了和最初设计的请求体结构保持一致,我们将signature和timestamp放在http请求的Header中传递。当Server端接收到数据时:
timestamp
{error_code:101010, error_msg:"request too old"}
采用消息验证码提高移动端和服务器数据交互的安全性
以前一直都有一个疑问,如果客户端在和服务器端进行通信时,如果在中途客户端发送给服务器端的数据被不法分子拦截到了,然后不法分子修改了我的请求数据,再发送给服务器。那岂不是很危险,有没有什么方式来避免这种情况。举个例子,假设我登录网上银行进行转账操作,我想向'Milo'转1000元,于是我的操作向Server端送的数据是{from:'Fred', to:'Milo', amount: 1000},假设有不法分子'Abhi'截取到了这个数据报,然后把它改成{from:'Fred', to:'Abhi', amount: 90000}。于是情况就糟高了,银行在完全不知情的情况下,把我的钱转出了90000给'Abhi'。接着各种纠纷便来了。如何解决这个问题呢?
我记得之前在做一个APP,我们会调用到腾讯微博的API, 在腾讯微博中有一个上传多张图片(记得不清楚)的API,是属于一个高级接口,在调用时,腾讯要求开发者将请求的参数字段名的升序进行排列,然后采用SHA1算法生成消息摘要,或者说进行签名,将签名数据附在URL后传过去。当时,自己还不是很理解为什么要这样,后来在实际项目中也碰到了采用这种方式,提高数据交互的安全性。在此记录一下。
还是回到最初的这个问题,我们可以采用如下思路,当A想要将数据传递给B时,在发送数据的同时,把对应的消息摘要也发送过去。当B接收到数据时,根据传过来的数据重新计算消息摘要,然后比对A传过来的消息摘要,如果二者一致,则认为当前请求的数据是安全的,然后进行相应的处理。消息摘要的生成可以采用多种算法,如HmacHash256, MD5,SHA1等。
具体做法如下:
{from:'Fred', to:'Milo', amount: 1000}
,首先按照参数的升序,依次是amount, from, to 对应的字段,假设我们为了使可读性更好,决定在每两个字段间用竖线(|)隔开。依照这个规则,构造原始数据为1000|Fred|Milo
。ABCDEFGHIJK
, 数据1000|Fred|Milo
生成的消息摘要为6ffa87395f4679512163b502be3921db5b085fae05f46a7fe22f111b7dadd586
http://chinabank.com/tranfer
. 我们采用POST方式提交数据,请求体是一个JSON, 原本为{from:'Fred', to:'Milo', amount: 1000}
,由于我们采用了消息摘要,于是此时的请求体为{from:'Fred', to:'Milo', amount: 1000, signature:'6ffa87395f4679512163b502be3921db5b085fae05f46a7fe22f111b7dadd586'}
。当服务器端拿到这个数据后。会重新利用HmacHash256算法,采用ABCDEFGHIJK
生成摘要,然后将生成的摘要请求体中的signature
进行比对,如果相同则处理本次请求,如果不同,则认为是非法请求,丢弃。以下是一段采用
HmacHash256
实现消息验证码的的代码片断:将byte数组转成String, 也可采用如下代码,其原理可以参看Java中byte与16进制字符串的互换原理:
我们是这么做的
在我们的项目中采用了类似上面的思路做了一个安全的enhancement。不过和上面的思路有一些区别。我们不仅会把这个加密后的数据
signature
传给Server端,同时还会把当前时间timestamp
传递过去。为了和最初设计的请求体结构保持一致,我们将signature
和timestamp
放在http请求的Header中传递。当Server端接收到数据时:timestamp
,如果发现timestamp
的值和和当前时间相差较大如(20分钟),便返回一个错误的消息如:{error_code:101010, error_msg:"request too old"}
。同时,timestamp
也是signature
明文的组成部份,这样可以避免重放攻击。timestamp
的值是在可以接受范围之类的,则开始提取请求体中的参数,按一定的顺序排列,然后再进行提取其消息散列码。signature
值,如果相同,则认为本次请求是合法,然后进行相应的业务处理,如果不相同,则认为本次请求是非法的,丢弃本次请求,或者执行其它的操作。