一个系统的权限控制严不严格,控制的合理不合理,从很大程序上决定了系统的稳定性程度与系统内部数据合法性程度。
我们今天不谈复杂的权限控制模型,仅就简单的权限控制做一些讨论。
一般网站的权限控制模型是这样的:一张菜单表,一张用户表,再来一张用户与菜单映射表。在用户登录后台时,通过用户-菜单映射表来查询出该用户所拥有的 权限菜单并展示给用户,同时将该用户登录信息保存至Session中。在分角色的后台管理系统中,一般还会在上述权限模型的基础上再增加一个角色表,将菜 单表与角色表关联起来,并根据这种关联方式实现其菜单可见性的控制。

那么再来看一下是如何判断用户是否合法的:
在ASP.NET 2.0 中,如果是使用Windows验证方式,那么在用户操作其他页面时,在页面Page_Onload之中去判断Session值是否为空,注意,仅仅是做了是否为空的判断。
在JSP之中,也可能是在页面init时进行Session值是否为空的判断。
仅仅判断为空,会有什么安全性问题?
上述情景,是最常见的一种权限控制方式,也是最简单的控制方式,但同时也是最不安全的一种。为什么?一个逻辑比较慎密的程序员会很快发现上述权限控制 模型存在的安全隐患。如果在一个机器上登录了两个相同的用户,那么在当前的IE7选项卡模式下,便会出现后一个登录用户的Session覆盖前一个登录用 户的Session,并且可以操作前一个用户的菜单。如果分角色的管理后台,那么便会很危险了。类似此种权限管理模型缺陷,或者叫”漏洞”的讨论,网上已 经很多了,在此不一一列举。

针对这种简单的权限管理模型,我们可以考虑如下几种解决方案:
1.修改权限管理模型
如果您的项目源码已经达到百兆级别,并且您想在您的系统中从根本上解决问题,那么建议您可以基于原有的权限模型进行一下权限控制的升级。具体方法我 想肯定许多人都能够想到,在每个页面判断Session值是否为空处做文章→每次不仅仅做是否为空的判断,而是需要判断当前Session下的用户是否有 操作该页面的权限。很好,难道需要每次都与数据库进行交互而进行权限的判断么?你可以这么做,但是我们程序员的大脑不仅仅是Coding用的,还需要去思 考。去考虑如何让自己的程序运行更有效率,如何让客户对我们的系统更满意。基于这种考虑,您一定想到的是在应用程序启动时 (asp.net:Application_OnStart JSP:可以设置一个随服务器启动而启动的Servlet)将权限表中的数据查询出来,放到缓存中然后在各个页面进行权限判断时从缓存中取数据而不是傻傻 的向数据库要数据去 :)
以上方案可以有效的避免没有权限操作某一页面的用户直接对一页面进行操作。但其缺点与是显而易见的,我们的权限——用户表中不可能细到每一个页面都有控制,仅仅是有限的几个菜单索引页面才能够有机会享有该特权。
2.控制同一客户端一次仅可以登录一个用户
怎么去控制?既然是在客户端做文章,那么很显然我们应该考虑到Cookie,而不是Session。如果在我提到”客户端控制”的时候,您想到了Session,那么很显然,是您对Cookie的功能了解不够深刻。
我们知道,仅同一域名下的Cookie才是可以共享的,二级域名下的其实也可以实现共享Cookie,只不过需要做一些简单的调整。显然一般情况下一 个简单的网站管理后台不可能像个人博客那样开启一个二级域名,我们要做的仅仅是读取该域名下的Cookie就可以了,根本不用考虑跨域名(确切的说,是跨 二级域名)操作Cookie的问题。
简单设想一下解决方案:在客户一登录时,写入Cookie,以标识为当前已经有用户登录,同时记录该用户的用户ID。再次打开登录界面或者执行登录动 作时,去查看用来标识是否有用户登录的Cookie是否存在,如果存在则通知登录者不可以同时登录两个用户。这样看似就解决了问题。
但事实上,这种解决方案也并非完美。我们应该考虑到,何时去清除Cookie,如果是在用户Logout时,那么强制关闭浏览器的行为怎么解决?强制 关闭进程的行为怎么解决?这个问题我想所有做过”单点登录”的兄弟们都应该有自己的看法,我就不重复网上已有文字了。针对那些非法退出系统的用户,在再次 登录时可以查看当前登录的用户ID和Cookie中保存的是否一致,如果一致的话,我们无需做任何的动作,因为同一个人的权限在短时间内是不太可能会发生 变化的(如果您非得较真说若是就在那一刻权限被调整了呢,那么我也没办法,不属于今天的讨论范围)。如果不一致,那么我们就应该去通知用户,告诉他已经有 其他用户在此机器上登录过并且没有正常退出,然后默认以下两条路您自己选:
1.主动清除Cookie,让该客户登录。但是这时候还是会有可能发生权限上的问题。
2.通知用户,让另一已经登录的用户在本机上再次登录并执行正常的退出。

其实以上说的都是一种亡羊补牢的方案,如果在系统设计之初就能够考虑得更全面一些就不会有以上两个方案 :D,尤其是在设计一个将来有可能发展成为产品的业务系统的时候更应该在权限控制上做全面的考虑。

最后以一句话来结束本文:攻防之道,在于”攻”与”防”之间的乐趣。

Add:
昨天讨论关于通过判断Session是否为空来判断用户是否合法登录,这其实是一个最低级别的权限控制。不过要想达到当前用户Session失效的情况 下,开启另一选项卡登录该系统也不能使用已经失效的Session页面其实也不是一件难事。只需要用方案2″  2.控制同一客户端一次仅可以登录一个用 户”即可。

本文转载自 http://www.itjianghu.net/120107/40915817442129605.htm