原创 by fancyf(fancyray) http://blog.csdn.net/fancyf/
写完了《asp.net forms authentication所生成cookie的安全性》,觉得可以为forms的安全性松一口气了,结果最初提出问题的贴主又提到了一个问题:machinekey是怎样实现的?同一台虚拟主机上不同的web application所使用的machinekey是不是一样的?上次没想到这个为题,再做一下试验。
试验思路:在同一台电脑上新建一个webapplication,所绑定的域名不一样,也不在同一个应用程序池中。在新建的webapplication生成一个cookie,把值拿到原先的webapplication中看看能否通过验证。
试验过程:为了绑定不同的域名,在这台电脑上启动了dns服务,并将网络连接中的dns服务器指向了这台电脑的ip。根据formsauthenticationticket构造函数的原型:
public formsauthenticationticket(int version, string name, datetime issuedate, datetime expiration, bool ispersistent, string userdata, string cookiepath)
以及在getauthcookie(…)中的调用方法:
formsauthenticationticket ticket1 = new formsauthenticationticket(1, username, datetime.now, createpersistentcookie ? datetime.now.addyears(50) : datetime.now.addminutes((double) formsauthentication._timeout), createpersistentcookie, "", strcookiepath);
决定在测试页面上放两个文本框,一个是用户名txtusername2,一个是时间txtgendate(代替datetime.now),然后在generation按钮的click事件中这样写:
datetime gendate = datetime.parse(this.txtgendate.text);
formsauthenticationticket ticket1 = new formsauthenticationticket(1, this.txtusername2.text, gendate, gendate.addyears(50), true, "", "/");
this.lblencryptedcookie.text = formsauthentication.encrypt(ticket1);
运行发现,对相同的用户名和生成时间,formsauthentication.encrypt(ticket1)所得到的结果每次都不一样,但是每个结果都是有效的。
现在把这个页面拿到新建立的webapplication中运行,把得到的一组结果放在了原webapplication的login.aspx页面上:
<script language=javascript>
document.cookie="mylab=5623de03be6ee52298f721b181c83f77a97688bb5268602de80c1a3db07b7a1ffb828080bd0785b18bb8072996c2e241fd9a54f0addd8500c2c510db54c31a40c8614541a9cf9c1a";
</script>
在原webapplication程序中启动一个非登录页面(upload.aspx),结果正常跳转到了login.aspx页面。此时应该已经执行了上面的js程序,也就是说另一个程序中生成的cookie已经生效了。直接再次输入upload.aspx的url,结果通过了验证!此时通过iehttpheaders可以清楚地看到,浏览器发送的请求中有这个值"mylab=5623de03be6ee52298f721b181c83f77a97688bb5268602de80c1a3db07b7a1ffb828080bd0785b18bb8072996c2e241fd9a54f0addd8500c2c510db54c31a40c8614541a9cf9c1a"。
这说明,machinekey的确只与machine有关,而与webapplication无关。一个application生成的cookie也可以通过其他application的forms验证!值得担心的事情终于出现了。a和b两个webapplication在同一台电脑上的两个不同的虚拟主机,a中使用了forms验证。b只要执行:
datetime gendate = datetime.parse(this.txtgendate.text);
formsauthenticationticket ticket1 = new formsauthenticationticket(1, this.txtusername2.text, gendate, gendate.addyears(50), true, "", "/");
this.lblencryptedcookie.text = formsauthentication.encrypt(ticket1);
这样一段代码可以生成在a中合法的一个用户名所对应的cookie,b通过伪造cookie的方式向a发出请求,就可以通过a的验证,从而获的任何一个用户的权限!这一切都太简单了,不需要任何高深的技术,只要a和b在同一台电脑上!!!而且根据《asp.net forms authentication所生成cookie的安全性》得出的结论,a无论是修改b所冒用的用户的密码还是在a上注销这个用户,都无法阻止b的行为,除非禁用这个用户名,而且不让b获得任何一个合法的用户名才能避免再次被仿冒。
这下我是不敢在虚拟主机上仅仅使用forms验证了。如果你的asp.net主机上还有其他用户,还是尽快加强安全措施吧。forms验证根本就不是给虚拟主机的用户用的,也根本没有考虑虚拟主机的安全性。
免责声明:本文仅仅是从技术的角度来探讨系统的安全性,任何人对本文的使用仅限于加强自己的网站的安全性,不得利用本文的内容从事非法活动。且作者不承担任何人利用本文给第三方造成的损失。