水平权限漏洞的防护功能实现

先前曾发表过一遍介绍水平权限漏洞的文章:

水平权限漏洞的修复方案:http://www.cnblogs.com/hnsongbiao/p/3752617.html

"水平权限漏洞一般出现在一个用户对象关联多个其他对象(订单、地址等)、并且要实现对关联对象的CRUD的时候。开发容易习惯性的在生成CRUD表单(或 AJAX请求)的时候根据认证过的用户身份来找出其有权限的被操作对象id,提供入口,然后让用户提交请求,并根据这个id来操作相关对象。在处理 CRUD请求时,往往默认只有有权限的用户才能得到入口,进而才能操作相关对象,因此就不再校验权限了。可悲剧的是大多数对象的ID都被设置为自增整型, 所以攻击者只要对相关id加1、减1、直至遍历,就可以操作其他用户所关联的对象了。"

该文章主要是对水平权限漏洞产生的原因进行了一些分析,感兴趣的同学可以温习下。

这次在一个安全项目开发中,领导要求预防水平权限漏洞的产生,项目底层正好使用了通用权限管理底层代码。参考了上面文章的方法。

通过引用其底层代码的安全工具类对水平权限漏洞进行了预防。下面把代码分享下:

一、前端对userId,利用通用权限管理系统底层的方法DotNet.Utilities.SecretUtil.Encrypt方法加密。加密内部实现原理如下:

 1         /// <summary>
 2         /// DES数据加密
 3         /// </summary>
 4         /// <param name="targetValue">目标值</param>
 5         /// <param name="key">密钥</param>
 6         /// <returns>加密值</returns>
 7         public static string Encrypt(string targetValue, string key)
 8         {
 9             if (string.IsNullOrEmpty(targetValue))
10             {
11                 return string.Empty;
12             }
13 
14             var result = new StringBuilder();
15             var des = new DESCryptoServiceProvider();
16             byte[] inputByteArray = Encoding.Default.GetBytes(targetValue);
17             // 通过两次哈希密码设置对称算法的初始化向量   
18             des.Key = Encoding.ASCII.GetBytes(FormsAuthentication.HashPasswordForStoringInConfigFile
19                                                   (FormsAuthentication.HashPasswordForStoringInConfigFile(key, "md5").
20                                                        Substring(0, 8), "sha1").Substring(0, 8));
21             // 通过两次哈希密码设置算法的机密密钥   
22             des.IV = Encoding.ASCII.GetBytes(FormsAuthentication.HashPasswordForStoringInConfigFile
23                                                  (FormsAuthentication.HashPasswordForStoringInConfigFile(key, "md5")
24                                                       .Substring(0, 8), "md5").Substring(0, 8));
25             var ms = new MemoryStream();
26             var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
27             cs.Write(inputByteArray, 0, inputByteArray.Length);
28             cs.FlushFinalBlock();
29             foreach (byte b in ms.ToArray())
30             {
31                 result.AppendFormat("{0:X2}", b);
32             }
33             return result.ToString();
34         }

 

二、后台利用通用权限管理系统底层的方法DotNet.Utilities.SecretUtil.Decrypt 对前台传来的useId进行了解密,实现原理如下:

 1         /// <summary>
 2         /// DES数据解密
 3         /// 20140219 吉日嘎拉 就是出错了,也不能让程序崩溃
 4         /// </summary>
 5         /// <param name="targetValue"></param>
 6         /// <param name="key"></param>
 7         /// <returns></returns>
 8         public static string Decrypt(string targetValue, string key)
 9         {
10             if (string.IsNullOrEmpty(targetValue))
11             {
12                 return string.Empty;
13             }
14             // 定义DES加密对象
15             try
16             {
17                 var des = new DESCryptoServiceProvider();
18                 int len = targetValue.Length / 2;
19                 var inputByteArray = new byte[len];
20                 int x, i;
21                 for (x = 0; x < len; x++)
22                 {
23                     i = Convert.ToInt32(targetValue.Substring(x * 2, 2), 16);
24                     inputByteArray[x] = (byte)i;
25                 }
26                 // 通过两次哈希密码设置对称算法的初始化向量   
27                 des.Key = Encoding.ASCII.GetBytes(FormsAuthentication.HashPasswordForStoringInConfigFile
28                                                       (FormsAuthentication.HashPasswordForStoringInConfigFile(key, "md5").
29                                                            Substring(0, 8), "sha1").Substring(0, 8));
30                 // 通过两次哈希密码设置算法的机密密钥   
31                 des.IV = Encoding.ASCII.GetBytes(FormsAuthentication.HashPasswordForStoringInConfigFile
32                                                      (FormsAuthentication.HashPasswordForStoringInConfigFile(key, "md5")
33                                                           .Substring(0, 8), "md5").Substring(0, 8));
34                 // 定义内存流
35                 var ms = new MemoryStream();
36                 // 定义加密流
37                 var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
38                 cs.Write(inputByteArray, 0, inputByteArray.Length);
39                 cs.FlushFinalBlock();
40                 return Encoding.Default.GetString(ms.ToArray());
41             }
42             catch
43             {
44             }
45             return string.Empty;
46         }

 

可以看到,在加密和解密方法中,我使用了用户的密码作为秘钥,这样对水平权限漏洞的预防会更好。

通用权限底层对安全防护做的很完美,大家合理利用,可预防常见安全问题的产生。

 

对于水平权限漏洞的预防,大家如果有更好的方法,欢迎交流~~,上面提供的底层方法,大家可以直接在项目中使用。

 

posted @ 2015-03-12 23:28  三人成虎  阅读(2073)  评论(1编辑  收藏  举报