shensr

软件推动科技,科技改变世界!

博客园 首页 新随笔 联系 订阅 管理
我在前一篇文章(Reflection带来的潜在威胁)中提到了通过Reflection访问private member所带来后果,这里接着这个话题来讨论应付这一问题的方法!

方法一:毫无疑问,那就是尽量不要把机密的代码发布出去。这也是最可靠的方法,然而很多情况下,我们做不到这一点,遇到这种情况我们也只好继续寻求其他解决方式……

方法二:通过制定StrongNameIdentityPermissionAttribute(感谢hBifTs提供的文章)来限制调用者的范围,如下所示:

[StrongNameIdentityPermissionAttribute(SecurityAction.Demand, PublicKey="002400000...")]
private static string Decrypt(byte[] d)
{
}

这时直接访问的话,runtime会扔出SecurityException。但遗憾的是,调用者可以在调用前通过如下语句关闭安全检查:

SecurityManager.SecurityEnabled = false;

这样一来,我们的安全设置依然形同虚设。根据这种方法的原理--检查被调用者的身份,我想到了下面方法:

方法三:在System.Diagnostics名字空间下有一个StackTrace的东东(我前不久刚用它写了一个写日志时详细记录Stack的辅助类,过两天我会把这个东东也Post上来 -- 哈哈,做了一次广告!),有了它,我们便可以得到调用者的信息,然后……好,废话少说,看看代码就知道了:

private static string Decrypt(byte[] d)
{
CheckCaller("SecLib, Version=1.0.1713.28332, Culture=neutral, PublicKeyToken=null");
...
}

private static void CheckCaller(string fullName)
{
StackTrace st = new StackTrace(2, false);
StackFrame sf = st.GetFrame(0);
MethodBase mb = sf.GetMethod();

if(mb.DeclaringType.Assembly.FullName != fullName)
throw new Exception("Invalid caller!");
}

这样我们便相当于自己强制做了一次调用者身份检查,而这一检查显然不会受系统的安全设置的影响。我这里使用Assembly.FullName来判断调用者是否合法,当然你完全可以使用别的逻辑,比如判断调用者是否是通过Reflection方式等等。

最后总结一下,方法一无疑是最可靠的,因此能遵循就尽量遵循。方法二无法起到保护作用,这里列出来只是表明方法三的思路来源于前者。方法三能基本达到我们的目的,但有许多局限性,如:别人依然可以通过Reflection看到我们的代码(用人说发布前使用混淆器,当然可以,不过保护代码不是本文关心的事情);或者运用各种手段跳过我们的检查……没有办法,既然你要在大街上走,就无法完全避免被人偷拍:)


下载该例子的完整代码:ReflectionTrap1.zip
posted on 2004-09-10 12:12  shensr  阅读(1439)  评论(1编辑  收藏  举报