Как использовать хешированные идентификаторы в Entity Framework в веб-приложении ASP .NET MVC 5.1, чтобы избежать предсказуемых ссылок на записи в базе данных

У меня класс модели:

 public class Person {
        public int Id { get; set; }
  ...
 }

и чтобы увидеть подробности о человеке, пользователь может угадать его 'id

http://localhost:17697/Person/Details/2

они просто последовательные целые числа.

Как я могу сказать Entity Framework, что нужно перетасовать эти идентификаторы, чтобы их было труднее угадать?


person ASP NET    schedule 15.09.2014    source источник
comment
Если вам не нужны предсказуемые идентификаторы, используйте guid. Это также поднимает вопрос, почему вам не нужны предсказуемые идентификаторы. Что вы пытаетесь предотвратить, поскольку единственное требование к первичному объекту - это его уникальность.   -  person Ben Robinson    schedule 15.09.2014


Ответы (4)


Если вам не нужны предсказуемые идентификаторы, вы можете использовать Guid вместо int. «Перемешивание» чрезмерно усложнит процесс и не даст вам никакой защиты.

Помните, что если вы пытаетесь защитить URL-адрес, напишите надлежащую безопасность, используя авторизацию и фильтры. Безопасность через неизвестность на самом деле ничего не защищает

person James Sampica    schedule 15.09.2014

Лично я использую в своих URL-адресах ярлыки, а не идентификаторы. Что-то типа:

http://localhost:17697/Person/Details/john-doe

Затем вы тянете объект на основе пули:

db.People.SingleOrDefault(m => m.Slug == slug);

Однако «безопасность посредством неизвестности» - не лучший план игры. Если идентификаторы «труднее угадать», это не решит проблему доступа к ним людей, которые не должны этого делать. Если данные должны быть защищены, реализуйте аутентификацию и укажите политику авторизации для действия.

person Chris Pratt    schedule 15.09.2014
comment
Авторизация завершена, пользователи смогут получить подробную информацию о человеке, которого я просто хочу, чтобы было сложнее запомнить идентификаторы. - person ASP NET; 15.09.2014

Поздно к вечеринке, но поскольку в ASP.NET MVC не так много об использовании HashIds, я поделюсь своим решением с использованием пользовательских классов ModelBinder и BaseModel. Конечный маршрут выглядит примерно как /example/voQ/details.

Сначала вам нужна модель, из которой ваши существующие модели могут расширяться и генерировать HashId;

public class abstract BaseModel
{
   private static readonly Hashids __hashId = new Hashids("seed", 2);

   public Id { get; set; }

   [NotMapped]
   public HashId
   {
     get { return BaseModel.__hashId.Encode(this.Id); }
   }
}

Связующее необходимо зарегистрировать в Global.asax для каждой модели:

ModelBinders.Binders.Add(typeof(ExampleModel), new ControllerModelBinder<ExampleModel>()); 

Затем действие может использовать модель напрямую, не беспокоясь о хэш-идентификаторе:

public ActionResult Details(ExampleModel model)
{
  return View(model);
}

Настройка ссылки такая же, но вместо передачи Id необходимо использовать свойство HashId из BaseModel.

@Url.Action("Details", new { id = item.HashId })

Наконец, папка модели:

public class ControllerModelBinder<T> : DefaultModelBinder
  where T : BaseModel
{

  public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
  {
    if (bindingContext.ModelType == typeof(T))
    {
      string hash = bindingContext.ValueProvider.GetValue("id").RawValue.ToString();

      if (!string.IsNullOrWhiteSpace(hash))
      {
        int id = HashIdHelper.ToInt(hash);

        if (id > 0)
        {
          using (ApplicationContext context = new ApplicationContext())
          {
            DbRawSqlQuery<T> query = context.Database.SqlQuery<T>(string.Format("SELECT * FROM {0} WHERE id = @Id LIMIT 1", EntityHelper.GetTableName<T>(context)), new MySqlParameter("@Id", id));

            try
            {
              T model = query.Cast<T>().FirstOrDefault();

              if (model != null)
              {
                return model;
              }
            }
            catch (Exception ex)
            {
              if (ex is ArgumentNullException || ex is InvalidCastException)
              {
                return base.BindModel(controllerContext, bindingContext);
              }

              throw;
            }
          }
        }
      }
    }

    return base.BindModel(controllerContext, bindingContext);
  }
}
person sixones    schedule 05.06.2015

Вы можете использовать HttpServerUtility.UrlTokenEncode и HttpServerUtility.UrlTokenDecode

Encode использует кодировку base64, но заменяет недружественные символы URL.

Аналогичный ответ есть в предыдущем вопросе SO. См. Принятый ответ. Справочник MSDN

person Tushar    schedule 15.09.2014
comment
Не могли бы вы показать, как его использовать в контроллере и посмотреть? - person ASP NET; 15.09.2014