NET应用——你的数据安全有必要升级
最近又被【现场破解共享单车系统】刷了一脸,不得不开始后怕:如何防止类似的情况发生?
想来想去,始终觉得将程序加密是最简单的做法。但是摩拜、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应用——你的数据安全有必要升级的更多相关文章
- 看完SQL Server 2014 Q/A答疑集锦:想不升级都难!
看完SQL Server 2014 Q/A答疑集锦:想不升级都难! 转载自:http://mp.weixin.qq.com/s/5rZCgnMKmJqeC7hbe4CZ_g 本期嘉宾为微软技术中心技术 ...
- 升级为iOS9后,默认请求类型为https,如何使用http进行请求会报错(引用他人的)
升级为iOS9后,默认请求类型为https,如何使用http进行请求会报错 The resource could not be loaded because the App Transport Sec ...
- IPv6 VS IPv4,谈谈升级 IPv6 的必要性
11月26日,中办.国办印发了<推进互联网协议第六版(IPv6)规模部署行动计划>,提出国内要在 5~10 年的时间形成下一代互联网自主技术体系和产业生态,建成全球最大规模的 IPv6 商 ...
- 开启 IPv6 新时代,升级后的 IPv6 厉害在哪?
IPv6,Internet Protocol Version 6,从字面翻译 “互联网协议第 6 版”,它是IETF设计的用于替代现行版本 IP 协议-IPv4 协议,被称作“下一代互联网协议”.早在 ...
- linux下mysql升级
最近漏洞扫描,扫描出了数据库存在中高危漏洞,于是迫切需要进行数据库升级.上网查了各种资料,说法很多,也到自己虚拟机上试了好多方法,终于倒腾出来,做下小总结记录一下. 升级操作: 1.到mysql官网h ...
- redis实战笔记(4)-第4章 数据安全与性能保障
本章主要内容 4.1 将数据持久化至硬盘 4.2 将数据复制至其他机器 4.3 处理系统故障 4.4 Redis事务 4.5 非事务型流水线( non-transactional pipeline) ...
- FinTech领域实践:乐维监控助力西南某上市城商行IT运维转型升级!
FinTech领域实践:乐维监控助力西南某上市城商行IT运维转型升级! 项目背景 随着信息化的逐步深入,企业业务运营活动对IT的依赖程度越来越高,传统的局部.粗放.碎片化的IT运维管理模式已经无法满足 ...
- 详解Linux运维工程师高级篇(大数据安全方向).
hadoop安全目录: kerberos(已发布) elasticsearch(已发布)http://blog.51cto.com/chenhao6/2113873 knox oozie ranger ...
- 今天升级Xcode 7.0 bata发现网络访问失败。
今天升级Xcode 7.0 bata发现网络访问失败.输出错误信息 The resource could not be loaded because the App Transport Securit ...
随机推荐
- 深入探析 Rational AppScan Standard Edition 多步骤操作
序言 IBM Rational AppScan Standard(下文简称 AppScan)作为面向 Web 应用安全黑盒检测的自动化工具,得到业界的广泛认可和应用.很多人使用 AppScan 时都采 ...
- 爬虫服务集群处理nginx返回504
最近在对爬虫服务做分布式服务的时候总是遇到服务器返回504,搞了两天才发现原来是nginx中有对超时的设置参数,自己都是用默认的,然而客户端的等待时间超过了nginx默认的超时设置 修改 keepal ...
- JSP动态合并单元格
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <table ...
- 51Nod 1080
#include "bits/stdc++.h" using namespace std; #define LL long long #define INF 0x3f3f3f3f3 ...
- II8部署WCF服务出错
环境:Windows 2012 R2 + IIS 8.0 + .NET 4.5 错误404.3 - Not Found: 控制面板->程序->启用或关闭Windows功能,如下图所示,将需 ...
- [洛谷P1822] 魔法指纹
洛谷题目连接:魔法指纹 题目描述 对于任意一个至少两位的正整数n,按如下方式定义magic(n):将n按十进制顺序写下来,依次对相邻两个数写下差的绝对值.这样,得到了一个新数,去掉前导0,则定义为ma ...
- Android中Handler导致的内存泄露
http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html Consider the follo ...
- CSS3禁止网页中文本被选中代码
通常大家会有js来实现,另一个方案就是,将-webkit-user-select 和-moz-user-select 的值设为none,这针对于移动用户,可能会很有用.请谨慎使用这个属性:因为大部分用 ...
- Linux网络编程之套接字基础
1.套接字的基本结构 struct sockaddr 这个结构用来存储套接字地址. 数据定义: struct sockaddr { unsigned short sa_family; /* addre ...
- OGRECave [www]
OGRECave https://github.com/OGRECave