最近又被【现场破解共享单车系统】刷了一脸,不得不开始后怕:如何防止类似的情况发生?

想来想去,始终觉得将程序加密是最简单的做法。但是摩拜、ofo也有加密,为什么仍然被破解?那是因为请求在传输过程中被篡改了关键参数,从而导致服务器做出了错误的响应。

如何防止篡改?自然是使用加密,加密方式的不同会决定篡改的成本(开头故事里的哥们大概用了2天),目前大多数的加密方法是暴露其他参数,只加密一个token,然后服务端验证token是否有效。从我的角度来讲,这种加密方式虽然破解难度很高,但多半是用MD5、SHA1、hmacMd5或AES等方式进行加密,结果往往是不可逆的,并且固定内容加密——不管多少次结果总是相同的。

对于部分人来讲,只要你暴露出来的数据就可以做很多事情了,而且如果使用这种加密手段,那么服务端和客户端必须约定好加密手段和参与加密的字段(规则),这就相当于:我(服务端)和你(客户端)一起设计了钥匙,然后在需要的时候(发起请求)你就往指定地方(服务器)丢一个上了锁的箱子(加密后的数据),然后我制作钥匙打开锁。我也可以丢箱子,然后你用同样方式去打开。

大家可以打开的锁安全么?想想都不靠谱。

更好的是什么?我们设想一下:我(服务端)给你(客户端)制造锁的图纸,我有制造钥匙的图纸,在你需要的时候(发起请求)就做一把锁,然后把货物(原始数据)放在箱子里锁好(加密完成)丢在指定的地方(服务器),然后我制作出钥匙,开锁拿走货物(解密)。

现在感觉如何?就像情报机构,侦察员只负责按照规则传递密码,而总部按照另一套规则解读,这个过程中就算被监听到,第三方也无法解读——这种方式就是今天要说的RSA。

该怎么做呢?很简单:基于现在基本都是用http交互数据,相互传输数据用json再好不过,所以我会要求客户端将所有参数以json格式全部拼装起来,然后整串加密后传输到服务器,请求内容看上去是这样的:

完全不知道这是一串什么鬼(如果我不是服务器的话):实际上这是一次登陆请求,里面包含账户、密码、时间戳、执行方法等,在服务端解密后是这样的:

{"msg":{"method":"log_in","time":"2017-09-28 10:30:27","user_name":"test","user_pwd":"test"}}

这就完成了一次正确的数据提交。并且如果有人修改了密文都会导致服务端解密失败从而驳回请求。这种情况下,就算你破译了整套客户端,也仅仅能拿到一个公钥,而远在服务端的私钥还是好好的(除非你已经攻破了人家的服务器),从而阻止参数在传递过程中被篡改(下面上点干货)。

生成公私钥:

    /// <summary>
/// RSA 的密钥产生 产生私钥 和公钥
/// </summary>
/// <param name="priKeys">私钥</param>
/// <param name="pubKey">公钥</param>
public static void rsaKey(out string priKeys, out string pubKey)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
priKeys = rsa.ToXmlString(true);
pubKey = rsa.ToXmlString(false);
}

RSA加密:

    /// <summary>
/// RSA加密(不限长度)
/// </summary>
/// <param name="publicKey">公钥</param>
/// <param name="text">要加密的文本</param>
/// <param name="enc">编码方式</param>
/// <returns>密文</returns>
public static string rsaEncrypt(string pubKey, string text, Encoding enc)
{
using (var rsaProvider = new RSACryptoServiceProvider())
{
var inputBytes = enc.GetBytes(text);
rsaProvider.FromXmlString(pubKey);
int bufferSize = (rsaProvider.KeySize / ) - ;
var buffer = new byte[bufferSize];
using (MemoryStream inputStream = new MemoryStream(inputBytes), outputStream = new MemoryStream())
{
while (true)
{
int readSize = inputStream.Read(buffer, , bufferSize);
if (readSize <= )
{
break;
}
var temp = new byte[readSize];
Array.Copy(buffer, , temp, , readSize);
var encryptedBytes = rsaProvider.Encrypt(temp, false);
outputStream.Write(encryptedBytes, , encryptedBytes.Length);
}
return Convert.ToBase64String(outputStream.ToArray());
}
}
}

RSA解密:

    /// <summary>
/// rsa解密
/// </summary>
/// <param name="priKey">私钥</param>
/// <param name="encrypted">要解密的字符串</param>
/// <param name="enc">编码方式</param>
/// <returns>明文</returns>
public static string rsaDecrypt(string priKey, string encrypted, Encoding enc)
{
if (string.IsNullOrEmpty(encrypted))
{
return string.Empty;
} if (string.IsNullOrWhiteSpace(priKey))
{
throw new ArgumentException("Invalid Private Key");
} using (var rsaProvider = new RSACryptoServiceProvider())
{
var inputBytes = Convert.FromBase64String(encrypted);
rsaProvider.FromXmlString(priKey);
int bufferSize = rsaProvider.KeySize / ;
var buffer = new byte[bufferSize];
using (MemoryStream inputStream = new MemoryStream(inputBytes),
outputStream = new MemoryStream())
{
while (true)
{
int readSize = inputStream.Read(buffer, , bufferSize);
if (readSize <= )
{
break;
} var temp = new byte[readSize];
Array.Copy(buffer, , temp, , readSize);
var rawBytes = rsaProvider.Decrypt(temp, false);
outputStream.Write(rawBytes, , rawBytes.Length);
}
return enc.GetString(outputStream.ToArray());
}
}
}

因为本人对js也有一些兴趣,所以尝试着利用js与服务器交互,然鹅发现js需要java格式的公私钥,于是找到了转换公私钥的代码,亲测有效,在这里搬运下,利己利他:

    /// <summary>
/// RSA公钥格式转换(net转java)
/// </summary>
/// <param name="pubKey">net格式公钥</param>
/// <returns>java格式的公钥</returns>
public static string rsaPubKeyNet2Java(string pubKey)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(pubKey);
BigInteger m = new BigInteger(, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[].InnerText));
BigInteger p = new BigInteger(, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[].InnerText));
RsaKeyParameters pub = new RsaKeyParameters(false, m, p);
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub);
byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
return Convert.ToBase64String(serializedPublicBytes);
} /// <summary>
/// RSA私钥格式转换(net转java)
/// </summary>
/// <param name="priKey">net格式私钥</param>
/// <returns>java格式的私钥</returns>
public static string rsaPriKeyNet2Java(string priKey)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(priKey);
BigInteger m = new BigInteger(, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[].InnerText));
BigInteger exp = new BigInteger(, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[].InnerText));
BigInteger d = new BigInteger(, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("D")[].InnerText));
BigInteger p = new BigInteger(, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("P")[].InnerText));
BigInteger q = new BigInteger(, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Q")[].InnerText));
BigInteger dp = new BigInteger(, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DP")[].InnerText));
BigInteger dq = new BigInteger(, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DQ")[].InnerText));
BigInteger qinv = new BigInteger(, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("InverseQ")[].InnerText));
RsaPrivateCrtKeyParameters privateKeyParam = new RsaPrivateCrtKeyParameters(m, exp, d, p, q, dp, dq, qinv);
PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);
byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetEncoded();
return Convert.ToBase64String(serializedPrivateBytes);
}

进行转换需要用到一个三方类库,我的百度网盘里可以下载 http://pan.baidu.com/s/1b9Wy42,可以直接使用。

js的RSA加密也要用到一个库,在这里捎带贴一下:

    <script type="text/javascript" src="https://passport.cnblogs.com/scripts/jsencrypt.min.js"></script>
<script>
//实例化对象
var crypt = new JSEncrypt();
//设置私钥
crypt.setPrivateKey('你的RSA公钥'); $('#log_in').click(function () {
//拼装发送数据
var post_data = crypt.encrypt('{"msg":{"method":"log_in","time":"' + Tool.getNowTime() + '","user_name":"' + $('.name').val() + '","user_pwd":"' + $('.pwd').val() + '"}}');
//在这里发起你的请求
});
</script>

因为js可以被看到,所以你更需要RSA,因为全部被看到也无所谓了。希望对大家有帮助~

NET应用——你的数据安全有必要升级的更多相关文章

  1. 看完SQL Server 2014 Q/A答疑集锦:想不升级都难!

    看完SQL Server 2014 Q/A答疑集锦:想不升级都难! 转载自:http://mp.weixin.qq.com/s/5rZCgnMKmJqeC7hbe4CZ_g 本期嘉宾为微软技术中心技术 ...

  2. 升级为iOS9后,默认请求类型为https,如何使用http进行请求会报错(引用他人的)

    升级为iOS9后,默认请求类型为https,如何使用http进行请求会报错 The resource could not be loaded because the App Transport Sec ...

  3. IPv6 VS IPv4,谈谈升级 IPv6 的必要性

    11月26日,中办.国办印发了<推进互联网协议第六版(IPv6)规模部署行动计划>,提出国内要在 5~10 年的时间形成下一代互联网自主技术体系和产业生态,建成全球最大规模的 IPv6 商 ...

  4. 开启 IPv6 新时代,升级后的 IPv6 厉害在哪?

    IPv6,Internet Protocol Version 6,从字面翻译 “互联网协议第 6 版”,它是IETF设计的用于替代现行版本 IP 协议-IPv4 协议,被称作“下一代互联网协议”.早在 ...

  5. linux下mysql升级

    最近漏洞扫描,扫描出了数据库存在中高危漏洞,于是迫切需要进行数据库升级.上网查了各种资料,说法很多,也到自己虚拟机上试了好多方法,终于倒腾出来,做下小总结记录一下. 升级操作: 1.到mysql官网h ...

  6. redis实战笔记(4)-第4章 数据安全与性能保障

    本章主要内容 4.1 将数据持久化至硬盘 4.2 将数据复制至其他机器 4.3 处理系统故障 4.4 Redis事务 4.5 非事务型流水线( non-transactional pipeline) ...

  7. FinTech领域实践:乐维监控助力西南某上市城商行IT运维转型升级!

    FinTech领域实践:乐维监控助力西南某上市城商行IT运维转型升级! 项目背景 随着信息化的逐步深入,企业业务运营活动对IT的依赖程度越来越高,传统的局部.粗放.碎片化的IT运维管理模式已经无法满足 ...

  8. 详解Linux运维工程师高级篇(大数据安全方向).

    hadoop安全目录: kerberos(已发布) elasticsearch(已发布)http://blog.51cto.com/chenhao6/2113873 knox oozie ranger ...

  9. 今天升级Xcode 7.0 bata发现网络访问失败。

    今天升级Xcode 7.0 bata发现网络访问失败.输出错误信息 The resource could not be loaded because the App Transport Securit ...

随机推荐

  1. c++模板类编译错误

    最近想写一个c++模板类,实现一个有向图.依据惯例,类在头文件中声明,类的实现写在源文件中.可是编译的时候出现了如下错误: undefined reference to 通过谷歌发现,这是一个很常见的 ...

  2. 增强学习Reinforcement Learning经典算法梳理3:TD方法

    转自:http://blog.csdn.net/songrotek/article/details/51382759 博客地址:http://blog.csdn.net/songrotek/artic ...

  3. 「模板」网络最大流 FF && EK && Dinic && SAP && ISAP

    话不多说上代码. Ford-Fulkerson(FF) #include <algorithm> #include <climits> #include <cstdio& ...

  4. git高级用法

    1.git未保存的代码怎么切换分支? 2.两个分支的代码怎么合并?怎么解决冲突? 常见报错: 1.Merge failed : Some unreacked working tree files wo ...

  5. 【BZOJ】1598: [Usaco2008 Mar]牛跑步

    [题意]给定有向图,边严格从大编号指向小编号,求前k短路.n<=1000,m<=10000,k<=100. [算法]归并+拓扑排序||A*求第k短路 [题解]因为此题自带拓扑序的特殊 ...

  6. JS之window对象

    window对象 window属性: opener:打开当前窗口的源窗口,如果这个窗口是由别的网页点击链接跳转过来的,或者是从另外一个页面点击打开窗口打开的,opener就是找到源页面的.如果当前窗口 ...

  7. vue双向数据绑定的原理-object.defineProperty() 用法

    有关双向数据绑定的原理 关于数据双向绑定的理解:利用了 Object.defineProperty() 这个方法重新给对象定义了新属性,在操作新属性分别为为获取属性值(调用get方法)和设置属性值(调 ...

  8. Apache的Commons Lang和BeanUtils

    1.字符串的空判断 //isEmpty System.out.println(StringUtils.isEmpty(null));      // true System.out.println(S ...

  9. 【转】关于Scapy

    关于Scapy Scapy的是一个强大的交互式数据包处理程序(使用python编写).它能够伪造 或者解码大量的网络协议数据包,能够发送.捕捉.匹配请求和回复包等等.它可以很容易地处理一些典型操作,比 ...

  10. python模块 zipfile

    zipfile是python里用来做zip格式编码的压缩和解压缩的,由于是很常见的zip格式,所以这个模块使用频率也是比较高的zipfile里有两个非常重要的class, 分别是ZipFile和Zip ...