#c# #asp.net-mvc #parameter-passing
#c# #asp.net-mvc #передача параметров
Вопрос:
Я ищу безопасную альтернативу для querystring, где я передам параметр методу контроллера на том же контроллере и верну его как представление.
Представление категорий:
@foreach (Project.Framework.ModelClasses.productCategories productCategories in ViewBag.Categories)
{
@Html.ActionLink(productCategories.description, "Products", "Shop", new { id = "", categoryID = productCategories.categoryID, description = productCategories.description }, null)
}
Метод контроллера:
public ActionResult Products(string categoryID, string keyword, string description)
{
ViewBag.appPath = ConfigurationManager.AppSettings["appPath"].ToString();
Methods Methods = new Methods();
Methods.tokenHeader = (string)Session["token"];
Methods.cookieContainer = (CookieContainer)Session["cookies"];
Response shopnowProductsResponse = Methods.shopnowProductsGet(categoryID, keyword);
if (shopnowProductsResponse.Code == "000")
{
List<product> products = new List<product>();
products = (List<product>)shopnowProductsResponse.Data;
string FPRFlag = "0";
foreach (product product in products)
{
if (FPRFlag != "1")
{
if (product.FPRFlag == "1")
{
FPRFlag = product.FPRFlag;
}
}
else
{
goto nextState;
}
}
nextState:
ViewBag.FPRFlag = FPRFlag;
ViewBag.Description = description;
ViewBag.Products = products;
}
return View();
}
Примечание: ключевое слово является необязательным
Комментарии:
1. Какое значение «безопасный» вы используете в своем вопросе? (может быть, подписание данных решит эту проблему?)
2. В частности, было бы достаточно безопасно, если бы он был частью URL, отличной от строки запроса? Сделав его частью маршрута?
3. По соображениям безопасности я не могу передать какой-либо параметр через URL, потому что я передаю конфиденциальные данные.
4. Определите «безопасный». Вам нужно, чтобы это было скрыто от пользователя? Скрыто от кого-либо, отслеживающего трафик? Вам нужно иметь возможность выполнять проверки целостности? «Безопасный» означает много вещей.
5. Если это конфиденциальные данные, вам следует сохранить их на стороне сервера и поместить в сеанс. По определению все, что вы отправляете клиенту (браузеру), небезопасно. Вы, конечно, могли бы зашифровать его, но зачем проходить через все эти проблемы, когда вы могли бы просто сохранить его на стороне сервера.
Ответ №1:
Предполагая, что вы просто хотите закодировать эти ссылки таким образом, чтобы конечный пользователь не мог получить список всех данных вашего продукта из URL-адресов, вы можете добиться этого, используя заменяющий код в ссылке. Я бы использовал хэш-значение:
@foreach (Project.Framework.ModelClasses.productCategories category in ViewBag.Categories)
{
@Html.ActionLink(category.description, "Products", "Shop",
new {
hc = category.categoryID.GetHashCode()
})
}
Затем на контроллере вы просматриваете хэш-код вместо categoryID
.
Это все еще оставляет две проблемы:
- Хэш-код будет виден в адресной строке браузера.
- Список хэш-кодов будет одинаковым каждый раз.
Первый можно исправить с помощью промежуточного действия, которое преобразует хэш-код обратно в a categoryID
и сохраняет результат в Session
хранилище, а затем перенаправляет на Products
страницу:
public ActionResult SetCategory(int hc)
{
string catID = HashToCategoryID(hc);
Session["categoryID"] = catID;
return RedirectToAction("Products");
}
Это не только возвращает браузер пользователя на Products
страницу, но и гарантирует (в большинстве случаев), что SetCategory
URL-адрес даже не отображается в истории браузера. Как правило, история браузера даже не показывает, что он вообще ушел со Products
страницы, поэтому нажатие Back
кнопки приведет их со страницы туда, где они были до того, как они впервые вошли.
Другая проблема — не меняющиеся хэш-коды — может быть исправлена несколькими способами: добавление в хэш значения, которое будет меняться от посещения к посещению (например, идентификатор сеанса) или генерация случайных значений и сохранение их в Session
хранилище для поиска.
Например:
// after loading your products:
// something to salt the hash codes with:
string salt = (DateTime.Now - DateTime.Today).TotalMilliseconds.ToString();
// generate hash codes for all the product categories
var hashcodes = products.Select(p => new { h = (salt p.categoryID).HashCode(), c = p.categoryID });
// create hash->categoryID dictionary and save in Session
var hashtocat = hashcodes.ToDictionary(hc => hc.h, hc => hc.c);
Session["HashToCategory"] = hashtocat;
// create categoryID->hash dictionary and save in ViewBag
var cattohash = hashcodes.ToDictionary(hc => hc.c, hc => hc.h);
ViewBag["CategoryToHash"] = cattohash;
Теперь при каждой загрузке страницы вы будете получать другой набор значений хэша. Затем ваша генерация ссылок становится:
@{ // grab hashcode dictionary from ViewBag
Dictionary<string, int> hashcodes = ViewBag["CategoryToHash"] as Dictionary<string, int>;
}
@foreach (Project.Framework.ModelClasses.productCategories category in ViewBag.Categories)
{
@Html.ActionLink(product.description, "SetCategory", new { hc = hashcodes[product.categoryID] })
}
Фактически теперь у вас есть список одноразовых кодов, срок действия которых истекает, и они заменяются новыми каждый раз, когда пользователь повторно Products
посещает страницу. Вероятность того, что один и тот же код будет работать более одного раза для одной и той же категории, бесконечно мала, и если ссылка не будет нажата из того же сеанса, произойдет сбой.
Говоря о сбоях … вам нужно будет добавить туда кучу обработки ошибок.
Комментарии:
1. Перед этим ответом. Это то, что было сделано в моем проекте, но без использования хэша. Спасибо за ваш ответ. Теперь я думаю, есть ли вероятность, что пользователь из браузера может проникнуть внутрь этого метода.
2. Если вы генерируете хэши или случайные ключи для каждой загрузки страницы, то вы в безопасности. В лучшем случае они могут перечислить хэши / ключи, сгенерированные для текущей страницы, но это не даст им много информации о ваших реальных структурах данных.