问题
I am working of encrypting the parameters in MVC url..such as
http:/localhost:xxxx/Movies/Edit/1, encrypting the parameter value 1,assigned to id.
Basically What i followed is implementing the custom Action link which will encrypt the RoutedValueDictionary values based on salt string and prefix the encrpyted value with same text say Encrypt_ so output would be Encrypt_dfhwo=23nbsdkfhskdf.
so url would be
http:/localhost:xxxx/Movies/Edit/Encrypt_dfhwo=23nbsdkfhskdf
Implemented DefaultControllerFactory.CreateController,I am checking if routed values starts with prefix Encrypt_ then decrypt the value and then pass to controller.
Everything is working fine. the problem i see is if hacker manipulate the url and change the url to http:/localhost:xxxx/Movies/Edit/5(random number,which matches the record in database),then my controller will process the request without any decryption mechanism.
How to overcome this problem..do you guys see any potential loop hole here.
Any suggestion are most welcome.
回答1:
- What are you getting by encrypting the database record? It looks like the value can still be replayed.
- If you only want access to the record by encrypted value, decrypt it in your action not before it, and don't allow it by just the number in your action,
- A hacker can still send random values, with just the encrypted value allowed, and still learn to encrypt any value they want, there are many side channel attack possibilities, you need to use Authenticated Encryption in this case.
- You should use a url-safe base 64, your example doesn't look like that is the case.
If all you want is someone not being able to randomly guess the record value, use a high level encryption framework that gives you fewer choices to lessen encryption mistakes. I ported Google's Keyczar to C#, so that C# would have such a framework. It has authenticated encryption, which adds 41 bytes to your encryption for header, random IV, and tag, and by default uses a web safe base64.
回答2:
**Add A Folder with two classes
Class 1 : EncryptedActionParameterAttribute
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Web;
using System.Web.Mvc;
namespace MVCInvoicClient.Extensions
{
[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 = "jdsg432387#";
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());
}
}
}
class 2 : MyExtensions
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace MVCInvoicClient.Extensions
{
public static class MyExtensions
{
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);
}
}
if (htmlAttributes != null)
{
RouteValueDictionary d = new RouteValueDictionary(htmlAttributes);
for (int i = 0; i < d.Keys.Count; i++)
{
htmlAttributesString += " " + d.Keys.ElementAt(i) + "=" + d.Values.ElementAt(i);
}
}
//<a href="/Answer?questionId=14">What is Entity Framework??</a>
StringBuilder ancor = new StringBuilder();
ancor.Append("<a ");
if (htmlAttributesString != string.Empty)
{
ancor.Append(htmlAttributesString);
}
ancor.Append(" href='");
if (controllerName != string.Empty)
{
ancor.Append("/" + controllerName);
}
if (actionName != "Index")
{
ancor.Append("/" + actionName);
}
if (queryString != string.Empty)
{
ancor.Append("?q=" + Encrypt(queryString));
}
ancor.Append("'");
ancor.Append(">");
ancor.Append(linkText);
ancor.Append("</a>");
return new MvcHtmlString(ancor.ToString());
}
private static string Encrypt(string plainText)
{
string key = "jdsg432387#";
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());
}
}
}
**Controller**
Add this line above the controller class Example for your Index
[EncryptedActionParameter]
**In your View**
@Html.EncodedActionLink("Download Invoice", "FileDownload","DataFiles", new { id = item.DataFilesID }, null)
add a using statement
@using MVCInvoicClient.Extensions
来源:https://stackoverflow.com/questions/15055373/encryption-of-url-in-mvc-4