【原创】C#通用权限管理-程序安全检查,这些你一定要考虑到位

接触通用权限已经一年,现在使用已经很熟练,分享通用权限管理下面的一些好的开发思想。

安全漏洞对于一个小项目来说,可能不是特别的重视,对于一个大项目来说,这是特别重要需要注意的,特别是在项目开发中的就要警惕,下面我列举一些项目开发中需要注意的安全

  1. 页面文本框的检查,每个文本框填写的内容是什么类型就是必须用正则表达式进行强制限制,不能随便输入无用的信息,这是第一步
  2. 对于C/S的程序,我们可以直接用正则表达式来限制,对于B/S的页面程序,我们也是需要js验证和后台代码的验证,因为浏览器可以禁止js,让js不起作用,所以我们采取的方式就是两步走,js验证后,需要后台对数据还要严格的校验,防止恶意数据进入数据库,守好大门很重要。
  3. 接口调用安全,通过Post和Get调用接口,知道了服务器的外网IP可以直接调用,所以尽量使用内网,这个就是很大的安全隐患。
  4. 防止Sql注入,特别非数字的文本框,用户直接可以填写update语句,必须要检查,也可以通过限制文本框的字符长度来控制,有很多程序员总是忘记这一点,字符串长度要和数据库表中的字段通过计算的出来,不能太长也不能太短。

软件开发中,用到最多的两个HTML元素就是input文本框和button标签,当用户通过键盘,鼠标操作文本框将文字内容输入,点击提交我们需要第一步就进行数据校验。

  • B/S文本框

    需要的正则表达式用到每个文本框中,这里共享一个收集的比较好的正则表达式链接常用正则表达式

    通过一些页面安全检查工具进行检测,这里先列举我们开发中用到的安全检查工具AppScan Source,它的一些使用技巧,这里也给出一个链接,AppScan使用分享

  • C/S文本框

    开发DevExpress Winform程序的Dev提供了很好的正则限制,如图1

  • 接口安全

  当我们的接口通过外网调用的时候是很不安全的,别人知道了URL后可以很轻松的进行调用,由于公司短信接口现在是我负责,每天都在不停的调用发送短信的接口,很多客户端进行调动,产生的短信都有上万条,如果被黑客知道了,那这个就是短信的轰炸机了,所以为了安全起见在接口中做了一下处理,通过内网IP调用接口,外网IP停止使用,看下代码

1             //获取请求的Url地址
2             var ipAddress = DotNet.Business.Utilities.GetIPAddress(true);
3             //必须是内网Ip请求才可以调用接口,做安全检查,不符合要求,直接返回
4             if (!IpHelper.IsLocalIp(ipAddress))
5             {
6                 result = (int)MessageStatus.IpError;
7                 return result;    
8             }

代码其实没有特别多,就几行代码,这样就可以达到安全的要求了,客户端调用必须填写内网的域名或者IP请求地址,这样程序才能通过检查,我们来看下获取IP地址的这个方法,参数true就是代表了你的服务器是否启用了代理方式,一般服务器如果没有通过nginx代理的话就可以不填写了,如果服务器是被代理过的一定要填写true,这样才可以获取到请求客户端的真是IP地址。

 1         /// <summary>
 2         /// 获取客户端ip地址
 3         /// </summary>
 4         /// <param name="transparent">是否使用了代理</param>
 5         /// <returns>ip地址</returns>
 6         public static string GetIPAddress(bool transparent = false)
 7         {
 8             string ip = string.Empty;
 9             if (System.Web.HttpContext.Current != null)
10             {
11                 if (transparent)
12                 {
13                     if (HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null)
14                     {
15                         ip = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();
16                     }
17                 }
18                 if (string.IsNullOrWhiteSpace(ip))
19                 {
20                     if (HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null)
21                     {
22                         ip = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();
23                     }
24                     else
25                     {
26                         ip = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"].ToString();
27                     }
28                 }
29             }
30             return ip;
31         }

接下来我们看下检查是否是本地IP地址的方法,内网地址一般都是192.168等等开头的IP是服务器的内网地址,所以我们判断一下开头就可以得到是否是内网IP的结果。

 1         /// <summary>
 2         /// 检查是否是内网IP
 3         /// </summary>
 4         /// <param name="ipAddress"></param>
 5         /// <returns></returns>
 6         public static bool IsLocalIp(string ipAddress)
 7         {
 8             bool result = false;
 9             if (!string.IsNullOrEmpty(ipAddress))
10             {
11                 if (ipAddress.StartsWith("192.168.")
12                     || ipAddress.StartsWith("172.")
13                     || ipAddress.StartsWith("10."))
14                 {
15                     result = true;
16                 }
17             }
18             return result;
19         }    
  • Sql安全

对于前台请求的普通文本框,入库之前一定要做防止Sql语句检查,在通用权限管理的代码中,我们一般使用强类型的实体进行数据库的增删改查,不适用拼接Sql语句的方式进行数据库操作, 本人一直很反感拼接Sql然后提交数据库执行,虽然这个在调试的时候很好很快的找到Sql语句的错误在哪里,但是从程序严谨的角度思考这是不正确的,面向对象告诉我们多使用实体,多使用强类型。还在拼接Sql语句一般都是刚进入工作的菜鸟喜欢干的事情,所以开发中一定要多使用ORM快速开发框架(我个人推荐通用权限管理ORM开发框架),兼容多个数据库,可以灵活切换,执行速度快,UI层不拼接Sql语句,参数化查询,多表查询,分页。

对于Sql注入漏洞,可以参考一下 Sql注入漏洞对于我们提交到后台的参数值我们一定要做安全性检查。

 1         #region public static string SqlSafe(string value) 检查参数的安全性
 2         /// <summary>
 3         /// 检查参数的安全性
 4         /// </summary>
 5         /// <param name="value">参数</param>
 6         /// <returns>安全的参数</returns>
 7         public static string SqlSafe(string value)
 8         {
 9             value = value.Replace("‘", "‘‘");
10             // value = value.Replace("%", "‘%");
11             return value;
12         }
13         #endregion

看下完整的分页请求案例代码,这就是通用权限管理的一些安全小总结

        #region public ActionResult List(Pager pager, string beginDate, string endDate, string oldRecordKey, string newValue) 获取修改记录
        /// <summary>
        /// 获取修改记录
        /// </summary>
        /// <param name="pager">分页实体</param>
        /// <param name="beginDate">开始日期</param>
        /// <param name="endDate">结束日期</param>
        /// <param name="oldRecordKey">原主键值,一般是单号</param>
        /// <param name="newValue">修改后新的值</param>
        /// <returns></returns>
        public ActionResult List(Pager pager, string beginDate, string endDate, string oldRecordKey, string newValue)
        {
            var dt1 = DateTime.Now;
            var dbHelper = DbHelperFactory.GetHelper(BaseSystemInfo.BusinessDbType, BaseSystemInfo.BusinessDbConnectionString);
            var paramaterList = new List<KeyValuePair<string, object>>();
            var listWhere = new List<string>();//查询条件
            string conditions = null;
            //变更日期范围
            if (!string.IsNullOrEmpty(beginDate) && !string.IsNullOrEmpty(endDate))
            {
                listWhere.Add(string.Format("{0} BETWEEN TO_DATE({1}, ‘yyyy-mm-dd hh24:mi:ss‘) AND TO_DATE({2}, ‘yyyy-mm-dd hh24:mi:ss‘)", ZTO_MODIFYEntity.FieldCREATE_DATE, dbHelper.GetParameter("beginTime"), dbHelper.GetParameter("endTime")));
                paramaterList.Add(new KeyValuePair<string, object>("beginTime", DbLogic.SqlSafe(Convert.ToDateTime(beginDate + " 00:00:00").ToString(BaseSystemInfo.DateTimeFormat))));
                paramaterList.Add(new KeyValuePair<string, object>("endTime", DbLogic.SqlSafe(Convert.ToDateTime(endDate + " 23:59:59").ToString(BaseSystemInfo.DateTimeFormat))));
            }
            //原主键值
            if (!string.IsNullOrEmpty(oldRecordKey))
            {
                listWhere.Add(string.Format(" {0}  =  {1}", ZTO_MODIFYEntity.FieldRECORED_KEY_OLD, dbHelper.GetParameter(ZTO_MODIFYEntity.FieldRECORED_KEY_OLD)));
                paramaterList.Add(new KeyValuePair<string, object>(dbHelper.GetParameter(ZTO_MODIFYEntity.FieldRECORED_KEY_OLD), DbLogic.SqlSafe(oldRecordKey)));
            }
            //修改后新值
            if (!string.IsNullOrEmpty(newValue))
            {
                listWhere.Add(string.Format(" {0}  =  {1}", ZTO_MODIFYEntity.FieldVALUE_NEW, dbHelper.GetParameter(ZTO_MODIFYEntity.FieldVALUE_NEW)));
                paramaterList.Add(new KeyValuePair<string, object>(dbHelper.GetParameter(ZTO_MODIFYEntity.FieldVALUE_NEW), DbLogic.SqlSafe(newValue)));
            }
            //不是超级管理员或者高权限用户只能看自己的
            if (!HasRole())
            {
                listWhere.Add(string.Format(" {0}  =  {1}", ZTO_MODIFYEntity.FieldCREATE_MAN_ID, dbHelper.GetParameter(ZTO_MODIFYEntity.FieldCREATE_MAN_ID)));
                paramaterList.Add(new KeyValuePair<string, object>(dbHelper.GetParameter(ZTO_MODIFYEntity.FieldCREATE_MAN_ID), UserInfo.Id));
            }
            //获取排序字段
            var sortField = Request["sort"];
            if (string.IsNullOrEmpty(sortField))
            {
                sortField = ZTO_MODIFYEntity.FieldCREATE_DATE;
            }
            sortField += (" " + Request["direction"]);
            int totalRows;
            if (listWhere.Count > 0)
            {
                conditions += string.Join(" AND ", listWhere);//构建查询条件
            }
            //返回列名称
            var backFieldList = new[]
            {
                string.Format("({0}||‘-‘||{1}){0}",ZTO_MODIFYEntity.FieldTABLE_CODE,ZTO_MODIFYEntity.FieldTABLE_NAME),
                ZTO_MODIFYEntity.FieldCREATE_DATE,
                ZTO_MODIFYEntity.FieldRECORED_KEY_OLD,
                ZTO_MODIFYEntity.FieldCOLOUM_CODE,
                ZTO_MODIFYEntity.FieldCOLOUM_NAME,
                ZTO_MODIFYEntity.FieldVALUE_OLD,
                ZTO_MODIFYEntity.FieldVALUE_NEW,
                ZTO_MODIFYEntity.FieldCREATE_MAN
            };
            var dt = DbLogic.GetDataTableByPage(dbHelper, out totalRows, ZTO_MODIFYEntity.TableName, string.Join(",", backFieldList), pager.pageNo, pager.pageSize, conditions, paramaterList, sortField);
            Hashtable ht = BuildHt(dt, totalRows, dt1);
            return Json(ht, JsonRequestBehavior.AllowGet);
        }
        #endregion

好的ORM框架可以帮助我们在工作中应对一些简单的界面,节约时间,就是节约生命。

正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!旁边有“推荐”二字,你就顺手把它点了吧,相得准,我分文不收;相不准,你也好回来找我!

时间: 2024-08-25 04:30:01

【原创】C#通用权限管理-程序安全检查,这些你一定要考虑到位的相关文章

基于吉日嘎底层架构的通用权限管理Web端UI更新:参考DTcms后台界面

经一周的研究学习,看了国内的H+.HUI等,国外的PaperDashboardPro.Make.Metronic BootStrap等,最终选定用一个轻量的,适合中国人的,来自DTcms的后台管理UI来改造吉日嘎拉的通用权限管理Web端的UI. js+css+图片文件如下 新增一个Menu.ashx文件,用于输出当前用户权限可以查看的所有菜单. 新增Main.aspx文件用于主框架,所有内容也放在名为fraContent的iframe中.其它涉及的登录跳转小修改暂时略过. 有图有真相,先上图:

通用权限管理设计

权限设计(初稿)     1. 前言:     权限管理往往是一个极其复杂的问题,但也可简单表述为这样的逻辑表达式:判断"Who对What(Which)进行How的操作"的逻辑表达式是否为真.针对不同的应用,需要根据项目的实际情况和具体架构,在维护性.灵活性.完整性等N多个方案之间比较权衡,选择符合的方案.     2. 目标:     直观,因为系统最终会由最终用户来维护,权限分配的直观和容易理解,显得比较重要简单,包括概念数量上的简单和意义上的简单还有功能上的简单.想用一个权限系统

通用权限管理平台(2014版)

随着版本的不断完善及后期项目发展需要,通用权限管理平台2014版即将发布,届时期望各位的关注.新版本的采用MVC4+bootstrap3.0结构,界面美观漂亮,兼容目前市场上的主流浏览器,减少程序员对于界面方面的依赖,无需美工的参与即可实现比较漂亮的软件界面,另外也集成MVC的优点,在后续的章节中,我将一一介绍给各位,希望在以后的学习中大家相互指教与学习. 目前,新版本的研发工作已完成大半工作,由于是利用业余时间开发,所以进度不会如大家所想象的那么快,新版本计划在下个月末完成全部研发及测试工作,

通用权限管理设计 之 数据权限

阅读目录 前言 初步分析 通用查询机制 数据权限规则 实际应用 结语 前言 前一篇文章<通用权限管理设计 之 数据库设计方案>介绍了[主体]- [领域] - [权限]( who.what.how问题原型 ) 的设计思想 本文将对这种设计思想作进一步的扩展,介绍数据权限的设计方案. 权限控制可以理解,分为这几种 : [功能权限]:能做什么的问题,如增加产品.[数据权限]:能看到哪些数据的问题,如查看本人的所有订单.[字段权限]:能看到哪些信息的问题,如供应商账户,看不到角色. 部门等信息. 上面

通用权限管理设计 ( 数据库结构设计)

一,前言  权限管理系统的应用者应该有三种不同性质上的使用, A,使用权限 B,分配权限 C,授权权限 本文只从<使用权限>和<分配权限>这两种应用层面分析,暂时不考虑<授权权限>这种. 二,初步分析 用户和角色 说到权限管理,首先应该想到,当然要设计一个用户表,一个权限表.这样就决定了一个人有什么样的权限. 做着做着就会发现这样设计太过繁琐,如果公司里面所有员工都有这样的权限呢,每一个人都要配置?那是一件很痛苦的事情.因此再添加一个角色表,把某些人归为一类,然后再把权

通用权限管理设计 之 数据库结构设计

一,前言  权限管理系统的应用者应该有三种不同性质上的使用, A,使用权限 B,分配权限 C,授权权限 本文只从<使用权限>和<分配权限>这两种应用层面分析,暂时不考虑<授权权限>这种. 二,初步分析 用户和角色 说到权限管理,首先应该想到,当然要设计一个用户表,一个权限表.这样就决定了一个人有什么样的权限. 做着做着就会发现这样设计太过繁琐,如果公司里面所有员工都有这样的权限呢,每一个人都要配置?那是一件很痛苦的事情.因此再添加一个角色表,把某些人归为一类,然后再把权

通用权限管理平台权限控制--按钮权限

通用权限管理系统的重点在于如何更好的控制按钮操作权限,在下结合自己的平台经验,在使用MVC的环境下,使用自定义MVC控件,并且结合系统的权限控制于一体,减少业务在权限方面的控制,使对按钮权限的控制更加简洁. 通用权限控制系统的权限用户控件实现以后,在实际使用中如下所示: @Html.Eap().Button().Id("btnAdd").Name("添加").Class("easyui-linkbutton").IconClass("i

一款集代码生成器+权限管理+工作流+报表工具+APP小程序于一体的敏捷开发框架

XJR敏捷开发框架是一套集代码生成器+通用权限管理+工作流+即时通讯+报表工具+手机APP小程序开发于一体的敏捷开发框架.拖拽拉可视化操作配置,降低开发难度和缩短开发周期,提高80%以上的工作效率,提供源码,可无线扩展,轻松开发CRM.OA.ERP.WMS.小程序.电商管理后台等各种企业管理系统. 以下是这个敏捷开发框架的一些阐述: 技术特点 技术选型: 使用目前流行的多种web技术,包括springboot, JPA,Druid, Activiti,Lombok,swagger,poi,Web

系统权限管理设计 (转)

权限设计(初稿)      1. 前言:      权限管理往往是一个极其复杂的问题,但也可简单表述为这样的逻辑表达式:判断“Who对What(Which)进行How的操作”的逻辑表达式是否为真.针对不同的应用,需要根据项目的实际情况和具体架构,在维护性.灵活性.完整性等N多个方案之间比较权衡,选择符合的方案.      2. 目标:      直观,因为系统最终会由最终用户来维护,权限分配的直观和容易理解,显得比较重要简单,包括概念数量上的简单和意义上的简单还有功能上的简单.想用一个权限系统解