当前位置: 代码迷 >> C# >> 一个加密受权系统引发的思考.
  详细解决方案

一个加密受权系统引发的思考.

热度:405   发布时间:2016-04-28 08:27:32.0
一个加密授权系统引发的思考...

  最近项目中有个需求,大致说起来就是:公司上线了一个网站,但是需要对这个网站做使用时间限制,也就是常说的授权。

  由于时间紧迫,我的实现思路如下:

  1、编写注册机代码,用注册机形成授权文件,授权文件为一个xml字符串,包括开始时间与结束时间节点,然后用加密方法对形成的xml字符串加密

  2、将授权文件放到网站发布目录下,修改原网站中的代码,解析授权文件中加密的字符串并进一步判断

  实现代码如下:

 注册机部分代码:

    Base_64 bs = new Base_64();                DateTime dtkssj = dtpKssj.Value;                string ksrq = dtkssj.ToString("yyyy-MM-dd");                DateTime dtjssj = dtpJssj.Value;                string jsrq = dtjssj.ToString("yyyy-MM-dd");                string xmlString = "";                             xmlString += "<KSRQ>" + ksrq + "</KSRQ>";                xmlString += "<JSRQ>" + jsrq + "</JSRQ>";                string jmzf = bs.encrypt(xmlString);                string dirPath = Application.StartupPath;                string filePath = dirPath + "\\" + "授权文件,.ini";                if (!File.Exists(filePath))                {                    File.Create(filePath);                }                FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite);                StreamWriter sw = new StreamWriter(fs);                fs.SetLength(0);                sw.Write(jmzf);                sw.Close();                MessageBox.Show("注册成功");    

   注册机的主体实现思路如上文所说,用特定格式的xml字符串控制,然后用特定方式加密。

     加密类的部分代码:     

public string encrypt(string str)    {        int len = str.Length;        if (str == null)            return "";//throw new Exception("NULL pointer.");        if (len == 0)            return str;        string pTmp = "";        pTmp = str;        string dest = "";        for (int i = 0; i < len; i++)        {            char ch = pTmp[i];            int idx1 = ch >> 2 & 0x3f;            int idx2 = ch << 4 & 0x30;            dest += s_keys[idx1];            if (++i == len)            {                dest += s_keys[idx2];                break;            }            //ch = pTmp.charAt(i);            ch = pTmp[i];            idx1 = idx2 | ch >> 4 & 0xf;            idx2 = ch << 2 & 0x3f;            dest += s_keys[idx1];            if (++i == len)            {                dest += s_keys[idx2];                break;            }            ch = pTmp[i];            idx1 = idx2 | ch >> 6 & 0x3;            idx2 = ch & 0x3f;            dest += s_keys[idx1];            dest += s_keys[idx2];        }        return dest;//dest.toString();    }

  解密类的部分代码:     

public string decrypt(string str)    {        if (str == null)            return "";//throw new Exception("NULL pointer.");        int len = str.Length;        if (len == 0)            return str;        string dest = "";        //StringBuffer dest = new StringBuffer();        for (int j = 0; j < len; j++)        {            char ch = str[j];            int i;            for (i = 0; i < 64; i++)                if (s_keys[i] == ch)                    break;            char tempDest = (char)(i << 2);            if (++j == len)            {                dest += tempDest;                //dest.append(tempDest);                break;            }            ch = str[j];            for (i = 0; i < 64; i++)                if (s_keys[i] == ch)                    break;            tempDest |= Convert.ToChar(i >> 4);            dest += tempDest;            //dest.append(tempDest |= i >> 4);            int temp = (i & 0xf) << 4;            if (++j == len)                break;            ch = str[j];            for (i = 0; i < 64; i++)                if (s_keys[i] == ch)                    break;            dest += (char)(temp | i >> 2);            //dest.append((char)(temp | i >> 2));            temp = (i & 0x3) << 6;            if (++j == len)                break;            ch = str[j];            for (i = 0; i < 64; i++)                if (s_keys[i] == ch)                    break;            dest += (char)(temp | i);            //dest.append((char)(temp | i));        }        return dest;//dest.toString();    }

     网站部分解密授权文件部分代码:    

string dirPath = Server.MapPath("");        string filePath = dirPath + "\\" + "授权文件.ini";        if (!System.IO.File.Exists(filePath))        {            //没有授权文件 显示未授权        }        else        {            System.IO.StreamReader sr = new System.IO.StreamReader(filePath, Encoding.UTF8);            string content = sr.ReadToEnd().ToString();            sr.Close();            Base_64 bs1 = new Base_64();            string jmzf = bs1.decrypt(content);            System.Xml.XmlDocument xmldoc = new System.Xml.XmlDocument();//实例化一个XmlDocument对像            xmldoc.LoadXml(jmzf);            System.Xml.XmlNode xnKsrq = xmldoc.SelectSingleNode("KSRQ");            string ksrq = xnKsrq.InnerText;            System.Xml.XmlNode xnJsrq = xmldoc.SelectSingleNode("JSRQ");            string jsrq = xnJsrq.InnerText;            DateTime dtKsrq = Convert.ToDateTime(ksrq);            DateTime dtJsrq = Convert.ToDateTime(jsrq);            DateTime dtNow = DateTime.Now.AddDays(1);            int ks = DateTime.Compare(dtKsrq, dtNow);            int js = DateTime.Compare(dtJsrq, dtNow);            if (ks > 0 || js < 0)            {                //显示授权到期            }        }

     在网站代码中直接获取到这个授权文件,然后用对称的方式解密并判断授权的开始日期与结束日期与服务器日期做比对。

     总结:代码很简单,甚至是有点简陋,这里希望抛砖引玉,有没有更好的实现思路?这种用文件授权的方式进行的加密是不是容易被破解?。。。 

            还望各位赐教.....

18楼博客园团队
您好,建议在博问( http://q.cnblogs.com/ )中问一下
Re: IceNewMan
@博客园团队,已经将完整的实现思路和代码放了出来
17楼Orson
网站的发布目录下面?,,肯定是不安全的,先把你的授权文件读出来。,,你的加密是BASE64,很容易解密的,然后按照你的规则生成假面XML .
Re: IceNewMan
@Orson,如果不知道解密规则,以及公钥呢?
16楼Mike.Jiang
可以试试用数字签名的方式来搞,这种方式主要是要保护好你的私钥。,1gt;生成一对公钥/私钥,2gt;在发布程序时,先获取你配置文件的hash code。 然后用私钥对这个hash code进行签名。 把这个签名文本随便保存在哪,客户知道也没关系。,3gt;在程序起动时,读配置文件,重新计算hash code,然后用公钥、hash code、已有的签名 来验证这个配置文件是否是你生成的那个,并且没有被修改过。,,这样做的好处是,即使你的程序被反编译被人获得了公钥也没有关系。 因为他没有私钥。修改配置文件后,没办法生成对应签名。 并且这个私钥是在你本地生成的,不需要在网上传播,相对来说安全一些。
Re: 2727551894
@Mike.Jiang,反编译了,直接把你的验证代码注释了,当然如果程序主要逻辑实在服务端的就没办法了,而客户端程序(不联网的),再怎么弄也没用
Re: IceNewMan
@Mike.Jiang,多谢赐教 我改天试一试数字签名的方式,好像就是由一个公钥解密变成了公钥加密 私钥解密的方式吧?
Re: 冲杀
@Mike.Jiang,引用可以试试用数字签名的方式来搞,这种方式主要是要保护好你的私钥。,1gt;生成一对公钥/私钥,2gt;在发布程序时,先获取你配置文件的hash code。 然后用私钥对这个hash code进行签名。 把这个签名文本随便保存在哪,客户知道也没关系。,3gt;在程序起动时,读配置文件,重新计算hash code,然后用公钥、hash code、已有的签名 来验证这个配置文件是否是你生成的那个,并且没有被修改过。,,这样做的好处是,即使你的程序被反编译被人获得了公钥也没有关系。 因为他没有私钥。修改配置文件后,没办法生成对应签名。 并且这个私钥是在你本地生成的,不需要在网上传播,相对来说安全一...,签名是能放置伪造一个签名。。,但是 如果是能反编译的。。。人家把公钥替换掉就是了!,所以如果是JAVA和.NET之类的,请使用加壳吧。尽量保护!唉
15楼2727551894
能防止反编译的才行,其他的都没用
Re: IceNewMan
@2727551894,要是需要能防止反编译 只混淆代码没有用 只有加壳了,现在就是没有什么好的思路
14楼jan4984
这标题...引发的思考,就给我看这个?
Re: IceNewMan
@jan4984,我的本意是想知道实现方法 因为我自己都感觉目前的加密方式太简单了
13楼花海啊
我咋感觉很容易被破解呢,只是我感觉
Re: IceNewMan
@花海啊,是的 我也感觉很容易破解 ,但是,首先以我自己的水平无法如果不知道密钥无法皮杰,其次,想不到什么好的方式,类似客户端程序那种写入注册表或者查看MAC地址的授权方式
12楼绥山潇洒哥
mark
11楼Echofool
给你如下建议,仅供参考,我也没有实践过,理论上应该比较难破解了。,1、首先是加密算法推荐使用非对称加密,并且加密数据需要参入混淆参数。,2、代码部署的时候要混淆(特别注意该为私有的即私有,该内部类型的,用内部类型,这样混淆工具能达到更好的效果,推荐.NET Reactor)。,3、验证授权的机制的时候不要那么死板,可以在某几个地方开启几个单独的线程异步去验证,当发现没有授权时,做几个坏事即可,可以考虑,①、死循环;②、恶意操作:删除文件等等;③、发送报告,记录服务器环境,留证据可以起诉。,4、这个是重点了,验证授权的代码先用普通代码写好,然后改成用il的方式动态生成出来,如果你的il代码够长的,这个破解的成本就相当高了。,,,,最后说一句,值得吗?
10楼我是_用户名
公网运行的话,可以加个授权服务器。
Re: IceNewMan
@我是_用户名,由于类似一个机构的管理系统,所以不是在公网上跑,但是确实会出现内部人员使用外网访问的情况
9楼s3
我可以发表评论吗?非要登录,,搞毛的授权,你不就是想控制网站的使用嘛,你能保证你写了这个就可以控制?还是就可以彻底控制?,,教你个很简单的办法,谁写的代码没个漏洞啥的?留他几个只有做代码审计才能发现的漏洞。想要shell还是停站,随便你。,,客户都不晓得咋个回事,反正就是要找你处理。
Re: IceNewMan
@s3,你这个方法太高明了,但是现在就是需要用授权来控制 不能说在程序里面留漏洞
8楼缤纷
加密最好用非对称算法。公私钥那种。
7楼oooo0oooo0
这不是网站吗,在首页验证服务器时间不可以?,我读书少,不明白为啥搞的这么复杂。
6楼林选臣
研究这个没什么意义,再强大的加密都会被破解。,string jmzf = bs1.decrypt(content);,上面这句,解密算法直接就在客户端,反编译看下就知道算法是什么,要破解非常非常的容易。
Re: IceNewMan
@林选臣,我不是刻意研究加密算法的 只是项目中用到了,这个是对网站的授权,如果没有源码,貌似看不到解密方法把?
5楼沈赟
mark
4楼Yaphets1
学习一下
3楼火星大能猫
.NET目前有几个加壳工具,最新版的加壳,吾爱破解那边暂时没人公开破解
2楼气质优雅的猪
可以借鉴一下,OAuth2,SSO的做法。SSO负责认证授权。
Re: Engineer
@气质优雅的猪,引用可以借鉴一下,OAuth2,SSO的做法。SSO负责认证授权。,他这个是内网使用,开始我也想到用一个授权服务器,人家是内网的,只能在程序上做文章。
1楼凌晨的太阳
不要担心什么反编译之类的,对方如果有这个能力,那可能就不会需要你们来做这个网站。如果有这个能力,你再强的加密也没有什么用,因为只要if的地方改掉就好了。,,小人行为可以:1.到期随机删除部分文件,2 硬编码到期限制也没有什么关系,正人君子可以:1.到期随机删除部分文件,授权改删除日期,2 加密狗之类。
Re: IceNewMan
@凌晨的太阳,嗯 因为客户毕竟不是做开发的 所以不可能懂什么反编译之类的东西,我的初衷其实是想弄清楚这种原理,想知道成熟的网站加密怎么做,因为如果是客户端的程序你可以通过写入注册表以及通过mac地址等控制用户的授权行为,但是网站是跑在服务器上的,你不可能在用户的服务器里面写注册表吧...
  相关解决方案