【问题标题】:Encryption in MVC 5MVC 5 中的加密
【发布时间】:2015-08-18 00:12:11
【问题描述】:

我希望在查询字符串中加密和解密模型 ID 的参数。我已经阅读了几种不同的方法,但有些文章有点过时了。加密查询字符串的最佳方法是什么?

我已按照本文 [http://www.dotnettrace.net/2013/09/encrypt-and-decrypt-url-in-mvc-4.html],也在此 SO 问题中引用的方法中概述的方法进行了操作。 Encrypt Route Data in URL.

我的编码操作链接正常工作,但我不知道如何在我的控制器的重定向操作中使用相同的加密 ID。

我使用的方法是最好的方法吗?我想防止用户更改查询字符串中的 ID 以查看另一条记录。

//extension
 public static MvcHtmlString EncodedActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
    {
        string queryString = string.Empty;
        string htmlAttributesString = string.Empty;
        if (routeValues != null)
        {
            RouteValueDictionary d = new RouteValueDictionary(routeValues);
            for (int i = 0; i < d.Keys.Count; i++)
            {
                if (i > 0)
                {
                    queryString += "?";
                }
                queryString += d.Keys.ElementAt(i) + "=" + d.Values.ElementAt(i);
            }
        }

        object newRouteValues = new { q = Encrypt(queryString) };

        string url = UrlHelper.GenerateUrl(null, actionName, controllerName, null, null, null, new RouteValueDictionary(newRouteValues), htmlHelper.RouteCollection, htmlHelper.ViewContext.RequestContext, true);
        TagBuilder tagBuilder = new TagBuilder("a")
        {
            InnerHtml = (!String.IsNullOrEmpty(linkText)) ? HttpUtility.HtmlEncode(linkText) : String.Empty
        };
        tagBuilder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        tagBuilder.MergeAttribute("href", url);

        return new MvcHtmlString(tagBuilder.ToString(TagRenderMode.Normal));
    }


    private static string Encrypt(string plainText)
    {
        string key = "@m2qJzeyjXLBK!axPV$Bvg3QUP";
        byte[] EncryptKey = { };
        byte[] IV = { 55, 34, 87, 64, 87, 195, 54, 21 };
        EncryptKey = System.Text.Encoding.UTF8.GetBytes(key.Substring(0, 8));
        DESCryptoServiceProvider des = new DESCryptoServiceProvider();
        byte[] inputByte = Encoding.UTF8.GetBytes(plainText);
        MemoryStream mStream = new MemoryStream();
        CryptoStream cStream = new CryptoStream(mStream, des.CreateEncryptor(EncryptKey, IV), CryptoStreamMode.Write);
        cStream.Write(inputByte, 0, inputByte.Length);
        cStream.FlushFinalBlock();
        return Convert.ToBase64String(mStream.ToArray());
    }

//attribute
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class EncryptedActionParameterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {

        Dictionary<string, object> decryptedParameters = new Dictionary<string, object>();
        if (HttpContext.Current.Request.QueryString.Get("q") != null)
        {
            string encryptedQueryString = HttpContext.Current.Request.QueryString.Get("q");
            string decrptedString = Decrypt(encryptedQueryString.ToString());
            string[] paramsArrs = decrptedString.Split('?');

            for (int i = 0; i < paramsArrs.Length; i++)
            {
                string[] paramArr = paramsArrs[i].Split('=');
                decryptedParameters.Add(paramArr[0], Convert.ToInt32(paramArr[1]));
            }
        }
        for (int i = 0; i < decryptedParameters.Count; i++)
        {
            filterContext.ActionParameters[decryptedParameters.Keys.ElementAt(i)] = decryptedParameters.Values.ElementAt(i);
        }
        base.OnActionExecuting(filterContext);

    }

    private string Decrypt(string encryptedText)
    {
        string key = "@m2qJzeyjXLBK!axPV$Bvg3QUP";
        byte[] DecryptKey = { };
        byte[] IV = { 55, 34, 87, 64, 87, 195, 54, 21 };
        byte[] inputByte = new byte[encryptedText.Length];

        DecryptKey = System.Text.Encoding.UTF8.GetBytes(key.Substring(0, 8));
        DESCryptoServiceProvider des = new DESCryptoServiceProvider();
        inputByte = Convert.FromBase64String(encryptedText);
        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(DecryptKey, IV), CryptoStreamMode.Write);
        cs.Write(inputByte, 0, inputByte.Length);
        cs.FlushFinalBlock();
        System.Text.Encoding encoding = System.Text.Encoding.UTF8;
        return encoding.GetString(ms.ToArray());
    }
}

此 EncodedActionLink 正在按预期工作:

@Html.EncodedActionLink("Add Log", "CreateLog", "Logs", new { id = Model.id }, new { @class = "btn btn-success btn-xs" })

如何在控制器中加密 id?

    return RedirectToAction("Details", "Log", new { id = ENCRYPTEDIDHERE})

更新 ===

我应该添加 id 不是用户 ID。控制器已经在检查用户是否已登录并有权查看通话记录。

【问题讨论】:

  • 您是否考虑过,即使用户能够猜测属于另一个用户的资源的 id,系统也应该检查该用户是否应该有权访问该资源并返回 403 (或404,或您认为合适的任何代码)如果他们不应该访问?这是为了缓解不安全的直接对象引用攻击owasp.org/index.php/…
  • 为什么? (任何人都可以在地址栏中输入他们想要的任何内容)。如果用户无权访问具有该 ID 的项目,则抛出错误。
  • 加密在那里几乎毫无意义——只是不可猜测的、非顺序的 ID(如 Guid)应该以更低的成本/复杂性提供等效的保护。其余的应该通过适当的身份验证/授权来完成,例如建议cacho's answer
  • 有效积分。也许我只是把事情复杂化了。我的角色已经到位。

标签: c# asp.net-mvc encryption


【解决方案1】:

我认为访问列表在这里可能是一个不错的解决方案。

如果你对 URL 进行加密是通过隐蔽性来安全的,这意味着如果有人窃取了 URL 字符串 id 仍然能够看到该页面。

考虑一下 ACL 方法,例如,每个用户都可以有一个编辑个人资料页面 /profile/user/{id},您可以做的是使用 ACL 检查 {id} 是否等于用户 ID。

如果用户被授权,则返回页面内容。否则,返回HTTP Status 403 - Forbidden

查看此链接以获取 ASP .NET MVC 中的 ACL 信息:

Where to add the ACL handler in the MVC Architecture.

【讨论】:

  • id 不是用户的。它是数据库中通话记录的id
  • 这只是一个例子。 ID可以是任何东西。构建 ACL 的关键在于 ->“ID X 对给定对象 Y 拥有(或没有)权限”
  • 根据我如何设置我的角色,有权访问 id 4 的同一用户也将有权访问 id 5。我只是不想让他们轻松跳跃通过更改查询字符串来围绕记录。
  • 如果您只是想让遍历您的 ID (1,2,3,4,5,6) 变得更加困难,那么您可以创建一个随机 UUID。如果这对您来说足够安全,那应该没问题。我指定“一点”,因为总有人可以尝试猜测您的 UUID .....
  • UUID/Guid 是具有相当安全性的更简单的解决方案。与 int 相比,猜测正确的 GUID 需要 一点 时间:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-12
  • 1970-01-01
相关资源
最近更新 更多