2013-12-23 2 views
2

MVC를 사용하여 항목을 편집하기위한 CRUD 페이지 집합을 만들었지 만 사용자가 편집하는 항목이 무엇인지 확신 할 수 있는지 혼란 스럽습니다. 업데이트하기 위해 게시하는 항목과 동일합니다.ASP.NET MVC : 항목 편집이 동일한 항목 ID를 게시하도록 보장

현재 나는 그것의 모델을 채우는 것은 그래서 그것을 업데이트 할 수 EditItem 행동 물론 게시물의 항목 ID를 저장하는 HiddenFor 도우미 ...

을 가지고 있지만 그들이 갈 경우 어떤 일이 발생 그 숨겨진 ID를 편집하고 다른 것으로 변경하십시오. 액션 필터를 추가하여 액세스 권한이없는 항목을 편집하지 못하도록 할 수는 있지만 액세스 권한이있는 항목으로 ID를 변경하면 어떻게됩니까?

권한 오류가 아니며 데이터 무결성 오류입니다. 항목을 편집 할 때 GET에서 검색 한 항목이 POST과 일치하는지 확인하고 싶습니다.

올바른 방법은 무엇입니까?

답변

1

액세스 권한이 있다면 기본적으로 GUI를 통해 이미 수행 할 수있는 작업을하기 위해 기본적으로 "응용 프로그램을 해킹"합니다. 기본적으로 다른 항목을 편집하는 것과 같은 일입니다. 그리고 누군가가 클라이언트 측에서 소스 코드를 수정한다면, 이상한 일들이 일어날 수도 있습니다.

물론 서버 측 액세스 제어 및 유효성 검사가 있어야하며 잘못된 데이터는 거부됩니다. 그러나 그들이 통과 한 모든 것이 유효하다면, 왜 그들이 할 수 없게해야합니까? 실제로 할 수있는 일은 많지 않습니다. 요청은 요청입니다. 유효하다면 유효합니다. 그것이 어디서 왔는지에 상관없이.

피들러와 같은 소프트웨어에서 요청을 작성하면 어떻게됩니까? 그렇다면 웹 응용 프로그램을 보지 않고도 데이터를 수정할 수 있습니다. 처음부터 뭔가를 "편집"하는 것이 아닙니다.

0

나는이 질문에 답하기에는 너무 늦을 수 있으며 같은 문제에 직면하고 있으므로 다음과 같은 방법으로 이러한 문제를 피할 수 있습니다.

  1. 은 당신이 사용자뿐만 아니라 그 항목을 편집 할 수있는 권한이로 다른 항목을 쓰기를 통해 할 수 있도록 항목 Id와 포스트 사람 중에 다른 값으로 항목 Id를 변경해야했다. 이 문제를 피하기 위해 ItemId 기반의 Id는 덜 예측 가능합니다 (항목 ID의 해시 값과 마찬가지로이 해시는 키를 기반으로하므로 응용 프로그램의 각 페이지마다 다른 키가 있으므로 itemid가 동일하면 생성됩니다) 다른 해시 값).

  2. 이제 양식을 가져올 때. 먼저 ItemId를 가져 와서 키를 기반으로 해시 값을 얻은 다음 이전에 생성 된 값과 비교하십시오. 비교가 ItemId 또는 해시 값과 함께 실패하면 실패 요청이 끝납니다.

다음은 작은 예제입니다.

public static class HtmlHelperExtentions 
    { 
     public static MvcHtmlString GenerateIntegrityToken(this HtmlHelper htmlHelper, 
      string name , string valuefromwhichtokengenerate , string key) 
     { 
      var builder = new TagBuilder("input");    
      builder.MergeAttribute("type", "hidden"); 
      builder.MergeAttribute("name", "DataIntegrity_" + name); 
      builder.MergeAttribute("value", DataIntegrityHelper.GetTokenValue(valuefromwhichtokengenerate,key));    
      return MvcHtmlString.Create(builder.ToString(TagRenderMode.SelfClosing)); 
     } 
    } 

    public static class DataIntegrityHelper 
    { 
     public static bool IsValid(string value,string encryptedvalue,string key) 
     {   
      string tempEncryptedValue = GetTokenValue(value, key); 
      return string.Equals(tempEncryptedValue,encryptedvalue,StringComparison.InvariantCultureIgnoreCase); 
     } 

     public static string GetTokenValue(string value, string key) 
     { 
      if (string.IsNullOrEmpty(key)) 
       key = "[email protected]#6"; 
      else 
       key = "[email protected]#3" + key; 
      byte[] keys = System.Text.UTF8Encoding.UTF8.GetBytes(key); 
      byte[] messageBytes = System.Text.UTF8Encoding.UTF8.GetBytes(value); 
      HMAC mac = HMACSHA256.Create(); 
      mac.Key = keys; 
      byte[] hashBytes = mac.ComputeHash(messageBytes); 
      return ByteToString(hashBytes); 
     } 

     public static string ByteToString(byte[] buff) 
     { 
      string sbinary = ""; 

      for (int i = 0; i < buff.Length; i++) 
      { 
       sbinary += buff[i].ToString("X2"); // hex format 
      } 
      return (sbinary); 
     } 
    } 

예시 사람 모델.

public class Person 
    { 
     public int Id { get; set; } 
     public string DataIntegrity_Id { get; set; } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
    } 

보기 (사람.cshtml)

@using (Html.BeginForm()) 
{ 
    @Html.GenerateIntegrityToken("Id",Model.Id.ToString(),"Hello") 
    @Html.HiddenFor(cc=>cc.Id) 
    <br />  
    @Html.TextBoxFor(cc=>cc.FirstName) 
    <br /> 
    @Html.TextBoxFor(cc => cc.LastName) 
    <br /> 
    <input type="submit" /> 
} 

컨트롤러 작업

public ActionResult Person() 
     { 
      return View(new Person()); 
     } 

     [HttpPost] 
     public ActionResult Person(Person person) 
     { 
      if (Extentions.DataIntegrityHelper.IsValid(person.Id.ToString(), person.DataIntegrity_Id, "Hello")) 
      { 
       return View(person); 
      } 
      else 
      { 
       return Content("Data integrity validation fails."); 
      } 
     }