接觸通用權限已經一年,現在使用已經很熟練,分享通用權限管理下面的一些好的開發思想。
安全漏洞對於一個小項目來說,可能不是特別的重視,對於一個大項目來說,這是特別重要需要注意的,特別是在項目開發中的就要警惕,下面我列舉一些項目開發中需要注意的安全
軟件開發中,用到最多的兩個HTML元素就是input文本框和button標簽,當用戶通過鍵盤,鼠標操作文本框將文字內容輸入,點擊提交我們需要第一步就進行數據校驗。
需要的正則表達式用到每個文本框中,這裡共享一個收集的比較好的正則表達式鏈接常用正則表達式
通過一些頁面安全檢查工具進行檢測,這裡先列舉我們開發中用到的安全檢查工具AppScan Source,它的一些使用技巧,這裡也給出一個鏈接,AppScan使用分享
開發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語句一般都是剛進入工作的菜鳥喜歡干的事情,所以開發中一定要多使用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框架可以幫助我們在工作中應對一些簡單的界面,節約時間,就是節約生命。
正在看本人博客的這位童鞋,我看你氣度不凡,談吐間隱隱有王者之氣,日後必有一番作為!旁邊有“推薦”二字,你就順手把它點了吧,相得准,我分文不收;相不准,你也好回來找我!