【原创】C#通用权限管理-程序安全检查,这些你一定要考虑到位
接触通用权限已经一年,现在使用已经很熟练,分享通用权限管理下面的一些好的开发思想。
安全漏洞对于一个小项目来说,可能不是特别的重视,对于一个大项目来说,这是特别重要需要注意的,特别是在项目开发中的就要警惕,下面我列举一些项目开发中需要注意的安全
- 页面文本框的检查,每个文本框填写的内容是什么类型就是必须用正则表达式进行强制限制,不能随便输入无用的信息,这是第一步
- 对于C/S的程序,我们可以直接用正则表达式来限制,对于B/S的页面程序,我们也是需要js验证和后台代码的验证,因为浏览器可以禁止js,让js不起作用,所以我们采取的方式就是两步走,js验证后,需要后台对数据还要严格的校验,防止恶意数据进入数据库,守好大门很重要。
- 接口调用安全,通过Post和Get调用接口,知道了服务器的外网IP可以直接调用,所以尽量使用内网,这个就是很大的安全隐患。
- 防止Sql注入,特别非数字的文本框,用户直接可以填写update语句,必须要检查,也可以通过限制文本框的字符长度来控制,有很多程序员总是忘记这一点,字符串长度要和数据库表中的字段通过计算的出来,不能太长也不能太短。
软件开发中,用到最多的两个HTML元素就是input文本框和button标签,当用户通过键盘,鼠标操作文本框将文字内容输入,点击提交我们需要第一步就进行数据校验。
B/S文本框
需要的正则表达式用到每个文本框中,这里共享一个收集的比较好的正则表达式链接常用正则表达式
通过一些页面安全检查工具进行检测,这里先列举我们开发中用到的安全检查工具AppScan Source,它的一些使用技巧,这里也给出一个链接,AppScan使用分享
- C/S文本框
开发DevExpress Winform程序的Dev提供了很好的正则限制,如图1
- 接口安全
当我们的接口通过外网调用的时候是很不安全的,别人知道了URL后可以很轻松的进行调用,由于公司短信接口现在是我负责,每天都在不停的调用发送短信的接口,很多客户端进行调动,产生的短信都有上万条,如果被黑客知道了,那这个就是短信的轰炸机了,所以为了安全起见在接口中做了一下处理,通过内网IP调用接口,外网IP停止使用,看下代码
//获取请求的Url地址
var ipAddress = DotNet.Business.Utilities.GetIPAddress(true);
//必须是内网Ip请求才可以调用接口,做安全检查,不符合要求,直接返回
if (!IpHelper.IsLocalIp(ipAddress))
{
result = (int)MessageStatus.IpError;
return result;
}
代码其实没有特别多,就几行代码,这样就可以达到安全的要求了,客户端调用必须填写内网的域名或者IP请求地址,这样程序才能通过检查,我们来看下获取IP地址的这个方法,参数true就是代表了你的服务器是否启用了代理方式,一般服务器如果没有通过nginx代理的话就可以不填写了,如果服务器是被代理过的一定要填写true,这样才可以获取到请求客户端的真是IP地址。
/// <summary>
/// 获取客户端ip地址
/// </summary>
/// <param name="transparent">是否使用了代理</param>
/// <returns>ip地址</returns>
public static string GetIPAddress(bool transparent = false)
{
string ip = string.Empty;
if (System.Web.HttpContext.Current != null)
{
if (transparent)
{
if (HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null)
{
ip = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();
}
}
if (string.IsNullOrWhiteSpace(ip))
{
if (HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null)
{
ip = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();
}
else
{
ip = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"].ToString();
}
}
}
return ip;
}
接下来我们看下检查是否是本地IP地址的方法,内网地址一般都是192.168等等开头的IP是服务器的内网地址,所以我们判断一下开头就可以得到是否是内网IP的结果。
/// <summary>
/// 检查是否是内网IP
/// </summary>
/// <param name="ipAddress"></param>
/// <returns></returns>
public static bool IsLocalIp(string ipAddress)
{
bool result = false;
if (!string.IsNullOrEmpty(ipAddress))
{
if (ipAddress.StartsWith("192.168.")
|| ipAddress.StartsWith("172.")
|| ipAddress.StartsWith("10."))
{
result = true;
}
}
return result;
}
- Sql安全
对于前台请求的普通文本框,入库之前一定要做防止Sql语句检查,在通用权限管理的代码中,我们一般使用强类型的实体进行数据库的增删改查,不适用拼接Sql语句的方式进行数据库操作, 本人一直很反感拼接Sql然后提交数据库执行,虽然这个在调试的时候很好很快的找到Sql语句的错误在哪里,但是从程序严谨的角度思考这是不正确的,面向对象告诉我们多使用实体,多使用强类型。还在拼接Sql语句一般都是刚进入工作的菜鸟喜欢干的事情,所以开发中一定要多使用ORM快速开发框架(我个人推荐通用权限管理ORM开发框架),兼容多个数据库,可以灵活切换,执行速度快,UI层不拼接Sql语句,参数化查询,多表查询,分页。
对于Sql注入漏洞,可以参考一下 Sql注入漏洞,对于我们提交到后台的参数值我们一定要做安全性检查。
#region public static string SqlSafe(string value) 检查参数的安全性
/// <summary>
/// 检查参数的安全性
/// </summary>
/// <param name="value">参数</param>
/// <returns>安全的参数</returns>
public static string SqlSafe(string value)
{
value = value.Replace("'", "''");
// value = value.Replace("%", "'%");
return value;
}
#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框架可以帮助我们在工作中应对一些简单的界面,节约时间,就是节约生命。
正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!旁边有“推荐”二字,你就顺手把它点了吧,相得准,我分文不收;相不准,你也好回来找我!
【原创】C#通用权限管理-程序安全检查,这些你一定要考虑到位的更多相关文章
- C#通用权限管理-程序安全检查,这些你一定要考虑到位
接触通用权限已经一年,现在使用已经很熟练,分享通用权限管理下面的一些好的开发思想. 安全漏洞对于一个小项目来说,可能不是特别的重视,对于一个大项目来说,这是特别重要需要注意的,特别是在项目开发中的就要 ...
- 基于吉日嘎拉的通用权限管理Webform版老界面bug修复
虽然弄了新界面<基于吉日嘎底层架构的通用权限管理Web端UI更新:参考DTcms后台界面>,但老界面的一点菜单显示的问题还是让我这种强迫症揪心,终于今晚可以美美的睡觉了. 老代码用了Ses ...
- 基于吉日嘎底层架构的通用权限管理Web端UI更新:参考DTcms后台界面
经一周的研究学习,看了国内的H+.HUI等,国外的PaperDashboardPro.Make.Metronic BootStrap等,最终选定用一个轻量的,适合中国人的,来自DTcms的后台管理UI ...
- winform快速开发平台 -> 通用权限管理之动态菜单
这几个月一直忙APP的项目,没来得及更新项目,想想该抽出时间整理一下开发思路,跟大家分享,同时也希望得到宝贵的建议. 先说一下我们的权限管理的的设计思路,首先一个企业信息化管理系统一定会用到权限管理, ...
- EASYUI+MVC4通用权限管理平台--前言
经过多年的管理信息系统的开发工作,吸取了工作中遇到的一些问题,经过自己的总结,形成了一套比较完整的管理信息系统的通用权限管理基础开发平台. 在软件的开发过程中我们首先需要解决的是UI问题,其次是浏览器 ...
- EASYUI+MVC4通用权限管理平台
通用权限案例平台在经过几年的实际项目使用,并取得了不错的用户好评.在平台开发完成后,特抽空总结一下平台知识,请各位在以后的时间里,关注博客的更新. 1.EASYUI+MVC4通用权限管理平台--前言 ...
- (转)EASYUI+MVC4通用权限管理平台
原文地址:http://www.cnblogs.com/hn731/archive/2013/07/15/3190947.html 通用权限案例平台在经过几年的实际项目使用,并取得了不错的用户好评.在 ...
- 基于asp.net(C#)MVC+前端bootstrap+ztree+lodash+jquery技术-Angel工作室通用权限管理
一.Angel工作室简单通用权限系统简介 AngelRM(Asp.net MVC Web api)是基于asp.net(C#)MVC+前端bootstrap+ztree+lodash+jquery技术 ...
- java中通用权限管理设计(转)
原文地址:http://www.cnblogs.com/a7345678/archive/2008/09/25/1298838.html 转自博客园暗夜精灵-鬼才阁 实现业务系统中的用户权限管理 B/ ...
随机推荐
- Supervisor 的配置与使用
环境:ubuntu 14.04 lts http://supervisord.org/liunx 下有很多守护进程的工具,如 nohup,screen,supervisor 等,supervisor ...
- 使用vim 查看二进制文件
Vim 可以用来查看和编辑二进制文件 vim -b egenea-base.ko 加上-b参数,以二进制打开 然后输入命令 :%!xxd -g 1 切换到十六进制模式显示
- 介绍几个工作开发中封装的好用的android自定义控件
首先看效果图, 看下这两个界面,第一个中用到了一个自定义的FlowRadioGroup,支持复合子控件,自定义布局: 第二个界面中看到了输入的数字 自动4位分割了吧:也用到了自定义的DivisionE ...
- getRequestURI,getRequestURL的区别
转自:http://www.cnblogs.com/JemBai/archive/2010/11/10/1873764.html test1.jsp======================= &l ...
- 图解 & 深入浅出JavaWeb:事务必会必知
事务,大家所熟悉的事务(Transcation),基本上会就往Spring事务靠.其实Spring事务管理基于底层数据库本身的事务处理机制.数据库事务的基础,是掌握Spring事务管理的基础.这篇总结 ...
- python 教程_【python 基础教程详解】
Lesson 1 准备好学习Python的环境下载的地址是:www.python.org为了大家的方便,我在校内作了copy:http://10.1.204.2/tool/compiler&I ...
- SLAM中的EKF,UKF,PF原理简介
这是我在知乎上问题写的答案,修改了一下排版,转到博客里. 原问题: 能否简单并且易懂地介绍一下多个基于滤波方法的SLAM算法原理? 目前SLAM后端都开始用优化的方法来做,题主想要了解一下之前基于 ...
- WebKit内核分析之Page
参考地址:http://blog.csdn.net/dlmu2001/article/details/6213377 注:本系列博客是在原博主博客基础上增加了自己的理解和片段,可以看源博文获得清晰的结 ...
- android 中targetSdkVersion和与target属性的区别
AndroidMenifest.xml中targetSdkVersion和project.properties中的target属性的区别 在AndroidMenifest.xml中,常常会有 ...
- Android系统架构说明介绍
Android系统架构说明介绍 Android系统架构和一些普遍的操作系统差不多,都是采用了分层的架构,从他们之间的架构图看,Android系统架构分为四个层,从高层到低层分别是应用程序层.应用程序框 ...