权限控制,或者说访问控制,广泛应用于各个系统中。抽象地说,都是某个主体(subject)对某个客体(object)需要实施某种操作(operation),而系统对这种操作的限制就是权限控制。
在网络中,一般是通过路由设备或者防火墙建立基于IP的访问控制。这种访问控制的“主体”是网络请求的发起方(比如一台PC),“客体”是网络请求的接收方(比如一台服务器),主体对客体的“操作”是对客体的某个端口发送网络请求。这个操作能否执行成功,是受到防火墙ACL策略限制的。
在操作系统中,对文件的访问也有访问控制。此时“主体”是系统的用户,“客体”是被访问的文件,能否访问成功,将由操作系统给文件设置的ACL(访问控制列表)决定。比如在Linux系统中,一个文件可以执行的操作分为“读”、“写”、“执行”三种,分别由r、w、x表示。这三种操作同时对应着三种主体:文件拥有者、文件拥有者所在的文件组、其他用户。主体、客体、操作这三者之间的对应关系,构成了访问控制列表。
在Web应用中,根据访问客体的不同,常见的访问控制可以分为“基于URL的访问控制”、“基于方法(method)的访问控制”和“基于数据的访问控制”。
基于URL的访问控制是最常见的,实现比较简单。如下为在基于Java的Web应用中,可以通过增加一个filter实现:
//获取访问功能 String url=request.getRequestPath(); //进行权限验证 User user= request.getSession().get("user"); boolean permit=PrivilegeManager.permit(user,url); if(permit){ chain.doFilter(request,response); }else{ //可以转到提示界面 }
但是这种访问控制也存在问题。在正常情况下管理后台的页面只有管理员才能够访问。但这些系统未对用户访问权限进行控制,导致任意用户只要构造出了正确的URL(因为这些管理页面一般不会被链接到前台页面上),就能够访问到这些页面。这种情况下需要加上简单的“基于页面的访问控制”。
垂直权限管理:
访问控制实际上是建立用户与权限之间的对应关系,现在应用广泛的一种方法,就是“基于角色的访问控制(Role-Based Access Control)”,简称RBAC。
RBAC事先会在系统中定义出不同的角色,不同的角色拥有不同的权限,一个角色实际上就是一个权限的集合。而系统的所有用户都会被分配到不同的角色中,一个用户可能拥有多个角色。在系统验证权限时,只需要验证用户所属的角色,然后就可以根据该角色所拥有的权限进行授权了。
Spring Security中的权限管理,就是RBAC模型的一个实现。我们暂时只关注Spring Security的授权功能。
Spring Security提供了一系列的“Filter Chain”,每个安全检查的功能都会插入在这个链条中。在与Web系统集成时,开发者只需要将所有用户请求的URL都引入到Filter Chain即可。
Spring Security提供两种权限管理方式,一种是“基于URL的访问控制”,一种是“基于method的访问控制”。这两种访问控制都是RBAC模型的实现,换言之,在Spring Security中都是验证该用户所属的角色,以决定是否授权。
对于“基于URL的访问控制”,Spring Security使用配置文件对访问URL的用户权限进行设定,如下:
<sec:http> <sec:intercept-url pattern="/president_portal.do**" access="ROLE_PRESIDENT" /> <sec:intercept-url pattern="/manager_protal.do**" access="ROLE_MANAGER" /> <sec:intercept-url pattern="/**" access="ROLE_USER" /> <sec:form-login /> <sec:logout /> </sec:http>
不同的URL对于能访问其的角色有着不同的要求。
Spring Security还支持“基于表达式的访问控制”,这使得访问控制的方法更加灵活:
<http use-expressions="true"> <intercept-url pattern="/admin*" access="hasRole(‘admin‘) and hasIpAddress(‘192.168.1.0/24‘)" /> ... </http>
而“基于method的访问控制”,Spring Security则是使用Java中的断言,分别在方法调用前和调用后实施访问控制:
在配置文件中配置使其生效:
<global-method-security pre-post-annotations="enabled" />
使用的方法是在代码中直接定义:
@PreAuthorize("hasRole(‘ROLE_USER‘)") public void create(Contact contact);
一个复杂点的例子:
@PreAuthorize("hasRole(‘ROLE_USER‘)") @PostFilter("hasPremission(filterObject,‘read‘) or hasPermission(filterObject,‘admin‘)") public List<Contact> getAll();
Spring Security很强大,但是比较复杂,学习和维护成本都比较高。
与Spring Security使用配置文件管理权限不同,PHP的流行框架“Zend Framework”中使用的Zend ACL实现的基础权限管理提供的是API级的权限框架。其实现方法如下:
$acl=new Zend_Acl(); $acl->addRole(new Zend_Acl-Role(‘guest‘)) ->addRole(new Zend_Acl-Role(‘member‘)) ->addRole(new Zend_Acl-Role(‘admin‘)); $parents=array(‘guest‘,‘member‘,‘admin‘); $acl->addRole(new Zend_Acl_Role(‘someUser‘),$parents); $acl->add(new Zend_Acl_Resource(‘someRource‘)); $acl->deny(‘guest‘,‘someResouce‘); $acl->allow(‘member‘,‘someResource‘); echo $acl->isAllowed(‘someUser‘,‘someResource‘)?‘allowed‘:‘denied‘;
这种基于角色的权限管理(RABC模型),我们可以称之为“垂直权限管理”。
不同角色的权限有高低之分。高权限角色访问低权限角色的资源往往是被允许的,反之往往是被禁止的。如果一个本属于低权限角色的用户通过一些方法能够获得高权限角色的能力,则发生了“越权访问”。
水平权限管理:
权限管理其实是一个业务需求,灵活多变,单纯的垂直权限管理是不够的。比如以前优酷网就发生过用户越权访问问题。用户登录后,可以通过更改URL中数字id的值去查看和修改他人的信息。在这里,URL经过rewrite后将参数映射成URL路径,但这并不妨碍修改用户id来实现攻击。在这里,id代表资源的唯一编号,因此通过篡改id,就能改变要访问的资源。而优酷网显然没有检查这些资源是否属于当前用户。
在这个例子中,用户访问了原本不属于他的数据。
用户A与用户B可能都属于同一个角色RoleX,但是两者又各自拥有一些私有数据。在正常情况下,应该只有用户自己才能访问自己的私有数据。但是在RBAC这种“基于角色的访问控制”模型下,系统只会验证用户A是否属于角色RoleX,而不会判断用户A能否访问只属于用户B的数据。因此,发生了越权访问。这种问题称之为“水平越权管理问题”。
相对于垂直权限管理来说,水平权限问题出现在同一角色上。系统之验证了能访问数据的角色,既没有对角色内的用户做细分,也没有对数据的子集做细分,因此缺乏一个用户到数据之间的对应关系。由于水平权限管理是系统缺乏一个数据集的访问控制所造成的,因此水平权限管理又可以称之为“基于数据的访问控制”。
而数据集权限管理并没有很通用的解决方案。一个简单的数据级访问控制,可以考虑使用“用户组(Group)”的概念。比如一个用户组的数据只属于该组内的成员,只有同一用户组的成员才能实现对这些数据的操作。此外,还可以考虑实现一个规则引擎,将访问规则的控制写在配置文件中,通过规则引擎对数据的访问进行控制。
总之,水平权限管理问题,至今仍然是一个难题——它难以被发现,难以在统一框架下解决。
总之,无论选择哪种访问控制方式,在设计方案时都应该满足“最小权限原则”,这是权限管理的黄金法则。
OAuth简介:
OAuth是一个在不提供用户名和密码的情况下,授权第三方应用访问Web资源的安全协议。
OAuth与OpenID都致力于让互联网变得更加开放。OpenID解决的是认证问题,OAuth则更注重授权。认证与授权的关系其实是一脉相承的,后来人们发现,其实更多的时候真正需要的是对资源的授权。
常见的应用OAuth的场景,一般是某个网站想要获取一个用户在第三方网站中的某些资源或服务。
比如在人人网上,想要导入用户MSN里的好友,在没有OAuth时,可能需要用户向人人网提供MSN用户名和密码。但是,这种做法使得人人网会持有用户的MSN账户和密码。而OAuth则使得用户在不需要向人人网提供MSN用户名和密码的情况下,可以授权MSN将用户的好友名单提供给人人网。
在OAuth1.0中,涉及3个角色,分别是:
1.Consumer:消费方(Client)
2.Service Provider:服务提供方(Server)
3.User:用户(Resource Owner)
在新版本的OAuth中,又被称为Client、Server、Resource Owner。在上面的例子中,Client时人人网,Server是MSN,Resource Owner是用户。
举一个例子:
假设Jane在faji.com上有两张图片,她想将这两张图片分享到beppa.com,通过OAuth,这个过程是如何实现的呢?
Jane先在beppa.com上,选择要从faji.com上分享图片。在beppa.com后台,则会创建一个临时凭证(Temporary Credentials),稍后Jane将持此临时凭证前往faji.com。然后页面跳转到faji.com的OAuth页面,并要求Jane登录。注意,这里是在faji.com上登录!登陆成功后,faji.com会询问Jane是否授权beppa.com访问Jane在faji.com里的私有照片。如果Jane授权成功,faji.com会将Jane带来的临时凭证标记为“Jane已经授权”,同时跳转回beppa.com,并带上临时凭证。凭此,beppa.com知道它可以去获取Jane的私有照片了。
对于beppa.com来说,它首先通过Request Token去faji.com换取Access Token,然后就可以用Access Token访问资源了。Request Token是能用于获取用户的授权,Access Token才能用于访问用户的资源。
最后,Jane成功地将她的照片从faji.com分享到beppa.com上。(可以看看217页的图片帮助理解。)
参考书籍:《白帽子讲Web安全》
原文:https://www.cnblogs.com/wzy-ustc/p/14378868.html