OpenWrt系统安全改进<五> --- Web 访问权限分级
2015-06-10 08:54
615 查看
摘要
OpenWrt系统安全改进<四>中介绍的只是在UI层面对用户进行访问控制,对于深层次非法操作并不能起到保护效果。本节介绍针对不同的用户登录请求,使用不同用户启动luci进程,从而实现不同用户进行操作级别的访问控制。机制分析
web页面操作涉及到uhttpd和luci两个模块,uhttpd处理http报文,将cgi请求转给luci处理。从代码实现就可以看出这两个模块目前只是针对单用户:1 uhttpd在初始化时,由root用户启动,在调用cgi请求时,使用execl调用luci
2 luci的cache内容只保留一份。
在本实践中,创建admin(归为root用户组)和user两个用户,当uhttpd接收到登陆请求包,判断用户是否发生变化,如果是就清除luci的cache(否则luci会执行出错),使用su启动luci进程。
准备工作
创建用户和用户组,相关的脚本(可执行文件)针对不同用户组分配不同的权限。(注意:busybox中的ash和sh需要能够被所有用户可以执行,我采用了两份busybox,ash/sh link到所有用户可执行的busybox,其他link到只有同组用户可执行的busybox)
使能busybox的su
使能web ui的多用户登陆
具体操作可以参见OpenWrt系统安全改进<一>
实现不同用户身份执行luci
[csharp]view plaincopyprint?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
--- a/uhttpd.c
+++ b/uhttpd.c
@@ -243,6 +243,64 @@
return bound;
}
+#ifndef MULTI_USER
+extern void MU_dbg(char *info);
+void MU_dbg(char *info)
+{
+ #if 0
+ int fd = open("/debug",O_RDWR|O_APPEND);
+ char buf[128] = {0};
+ int len = strlen(info);
+
+ if (fd<0) {
+ fd = open("/debug",O_CREAT|O_RDWR);
+ }
+
+ memcpy(buf,info,len);
+ buf[len] = '\n';
+
+ write(fd,buf,len+1);
+ close(fd);
+ #endif
+}
+
+static char CUR_USER[32] = {0};
+
+extern void get_cur_user(char *user);
+void get_cur_user(char *user) {
+ if ( strlen(CUR_USER)==0 ) {
+ MU_dbg("CUR_USER empty");
+ strcpy(user,"admin");
+ } else {
+ memcpy(user,CUR_USER,strlen(CUR_USER));
+ }
+}
+
+static void MU_get_user(const
struct client *cl, char *user) {
+ char *usrhead = cl->httpbuf.ptr;
+ char *pwdhead = strfind(usrhead,strlen(usrhead),"&password=",strlen("&password="));
+
+ usrhead += strlen("username=");
+ memcpy( user, usrhead, pwdhead-usrhead );
+
+ MU_dbg(user);
+}
+
+static void MU_clear_luci_cache() {
+ int ret = 0;
+
+ ret = system("echo clear cache > /tmp/luci_action");
+ ret = system("rm -Rf /tmp/luci-*");
+ if ( ret == -1 ) {
+ system("echo fail >> /debug");
+ } else if ( ret==0 ) {
+ system("echo ignore >> /debug");
+ } else {
+ system("echo finish >> /debug");
+ }
+}
+#endif
+
static struct http_request * uh_http_header_parse(struct client *cl,
char *buffer, int buflen)
{
@@ -281,7 +339,21 @@
if (method && !strcmp(method,
"GET"))
req->method = UH_HTTP_MSG_GET;
else
if (method && !strcmp(method, "POST"))
- req->method = UH_HTTP_MSG_POST;
+ #ifndef MULTI_USER
+ {
+ char user[32] = {0};
+
+ MU_get_user(cl,user);
+ if( strncmp(user,CUR_USER,4)!=0 ) {
+ MU_clear_luci_cache();
+ }
+ memcpy(CUR_USER,user,32);
+
+ req->method = UH_HTTP_MSG_POST;
+ }
+ #else
+ req->method = UH_HTTP_MSG_POST;
+ #endif
else if (method && !strcmp(method,
"HEAD"))
req->method = UH_HTTP_MSG_HEAD;
else
--- a/uhttpd-cgi.c
+++ b/uhttpd-cgi.c
@@ -486,12 +486,32 @@
if (chdir(pi->root))
perror("chdir()");
+ #ifndef MULTI_USER
+ {
+ extern
void get_cur_user(char *user);
+ extern void MU_dbg(char *info);
+
+ char user[32] = {0};
+ char info[32] = {0};
+
+ get_cur_user(user);
+
+ sprintf(info,"exec via %s",user);
+ MU_dbg(info);
+
+ if (ip!=NULL) {
+ execl("/bin/su","su",user,"-c",ip->path,pi->phys,NULL);
+ } else {
+ execl("/bin/su","su",user,"-c",pi->phys,NULL);
+ }
+ }
+ #else
if (ip != NULL)
- execl(ip->path, ip->path, pi->phys, NULL);
- else
+ execl(ip->path, ip->path, pi->phys, NULL);
+ else
execl(pi->phys, pi->phys, NULL);
-
- /* in case it fails ... */
+ #endif
+ /* in case it fails ... */
printf("Status: 500 Internal Server Error\r\n\r\n"
"Unable to launch the requested CGI program:\n"
" %s: %s\n", ip ? ip->path : pi->phys, strerror(errno));
--- a/uhttpd.c +++ b/uhttpd.c @@ -243,6 +243,64 @@ return bound; } +#ifndef MULTI_USER +extern void MU_dbg(char *info); +void MU_dbg(char *info) +{ + #if 0 + int fd = open("/debug",O_RDWR|O_APPEND); + char buf[128] = {0}; + int len = strlen(info); + + if (fd<0) { + fd = open("/debug",O_CREAT|O_RDWR); + } + + memcpy(buf,info,len); + buf[len] = '\n'; + + write(fd,buf,len+1); + close(fd); + #endif +} + +static char CUR_USER[32] = {0}; + +extern void get_cur_user(char *user); +void get_cur_user(char *user) { + if ( strlen(CUR_USER)==0 ) { + MU_dbg("CUR_USER empty"); + strcpy(user,"admin"); + } else { + memcpy(user,CUR_USER,strlen(CUR_USER)); + } +} + +static void MU_get_user(const struct client *cl, char *user) { + char *usrhead = cl->httpbuf.ptr; + char *pwdhead = strfind(usrhead,strlen(usrhead),"&password=",strlen("&password=")); + + usrhead += strlen("username="); + memcpy( user, usrhead, pwdhead-usrhead ); + + MU_dbg(user); +} + +static void MU_clear_luci_cache() { + int ret = 0; + + ret = system("echo clear cache > /tmp/luci_action"); + ret = system("rm -Rf /tmp/luci-*"); + if ( ret == -1 ) { + system("echo fail >> /debug"); + } else if ( ret==0 ) { + system("echo ignore >> /debug"); + } else { + system("echo finish >> /debug"); + } +} +#endif + static struct http_request * uh_http_header_parse(struct client *cl, char *buffer, int buflen) { @@ -281,7 +339,21 @@ if (method && !strcmp(method, "GET")) req->method = UH_HTTP_MSG_GET; else if (method && !strcmp(method, "POST")) - req->method = UH_HTTP_MSG_POST; + #ifndef MULTI_USER + { + char user[32] = {0}; + + MU_get_user(cl,user); + if( strncmp(user,CUR_USER,4)!=0 ) { + MU_clear_luci_cache(); + } + memcpy(CUR_USER,user,32); + + req->method = UH_HTTP_MSG_POST; + } + #else + req->method = UH_HTTP_MSG_POST; + #endif else if (method && !strcmp(method, "HEAD")) req->method = UH_HTTP_MSG_HEAD; else --- a/uhttpd-cgi.c +++ b/uhttpd-cgi.c @@ -486,12 +486,32 @@ if (chdir(pi->root)) perror("chdir()"); + #ifndef MULTI_USER + { + extern void get_cur_user(char *user); + extern void MU_dbg(char *info); + + char user[32] = {0}; + char info[32] = {0}; + + get_cur_user(user); + + sprintf(info,"exec via %s",user); + MU_dbg(info); + + if (ip!=NULL) { + execl("/bin/su","su",user,"-c",ip->path,pi->phys,NULL); + } else { + execl("/bin/su","su",user,"-c",pi->phys,NULL); + } + } + #else if (ip != NULL) - execl(ip->path, ip->path, pi->phys, NULL); - else + execl(ip->path, ip->path, pi->phys, NULL); + else execl(pi->phys, pi->phys, NULL); - - /* in case it fails ... */ + #endif + /* in case it fails ... */ printf("Status: 500 Internal Server Error\r\n\r\n" "Unable to launch the requested CGI program:\n" " %s: %s\n", ip ? ip->path : pi->phys, strerror(errno));
实现admin执行UCI修改
完成上步操作后,使用不同用户登录可以根据用户执行LuCI,但是admin和user都只能查询UCI相关的一些配置,而我期望的admin能够修改配置。经过一些尝试,发现仅仅为admin赋予uci的执行权限和相关配置文件的写权限扔不能执行UCI修改操作(uci set/commit)。
我希望修改的配置是通过UCI Map来进行修改的,修改usr/lib/lua/luci/cbi.lua文件的Map.set和Map.parse,使用su权限来执行uci set 和 commit。
后续工作
目前实现虽然支持了多用户的操作权限控制,但是对于用户切换时访问效率低,后续可以修改luci,针对每个用户创建一份cache。相关文章推荐
- 第十四周(OOP版电子词典)
- openshift上安装nginx反向代理(失败记录)
- Sqoop用法
- openstack kilo keystone token问题及性能优化
- myBase Desktop Edition v5.3 不破解的破解
- stm32.cube(一)——系统架构及目录结构
- linux驱动增加work工作队列和获取唤醒锁操作
- Hadoop项目实战-用户行为分析之应用概述(二)
- Vim简明教程【CoolShell】
- Vim简明教程【CoolShell】
- hadoop的压缩解压缩,reduce端join,map端join
- 批量生成或合并gif格式图像的方法
- Linux 内核基础--List使用方法
- Nginx反向代理+DNS轮询+IIS7.5 千万PV 百万IP 双线 网站架构案例
- keepalived+nginx实现nginx的高可用
- semctl semget semop 函数系列构成的 信号量
- linux下安装squid代理服务器
- Nginx安全配置研究
- Nginx/LVS/HAProxy负载均衡软件的优缺点详解
- Nginx 战斗准备 —— 优化指南