質問

It has been some time i try figuring out this!
Generally: i want to get a "Readonly, Hidden" Property from my Form.

I Trimmed all that is unncessey from the example:
i have the following Model

public class ChangeOrderDetailModel
{
...
...
    [ReadOnly(true)]
    public int OrderId { get; set; }
}

and in the View:

@using (Html.BeginForm("SubmitChangeOrder", "Order"))
{
    @Html.AntiForgeryToken()<br/>
    @Html.HiddenFor(o => o.OrderId) <br />
...
...
}

Now:

  1. in the View HTML, there is a hidden field for OrderID...

  2. I dont want anyone to change "OrderID" cause it can cause security issues.

  3. I need the OrderID number at the form submit...

  4. Problem When the form is submitted to the Controller OrderController.SubmitChangeOrder(ChangeOrderDetailModel mdl){}
    i see that mdl.OrderID is always = 0.

  5. When I remove the ReadOnly(true) attribute from the propertie, everything works ok, but anyone can change the value of the field using simple JS, which is VERY BAD.
    and i dont want to relay only on a hash token cause it is easly broken too :(

Why is it working like this?
Am i missing something, a better way to achive what i like?

note: there might be several change orders going on in parallel so session is kinda problematic.

Thanks to all.

役に立ちましたか?

解決

By using [Readonly(true)] you are explicitly instructing the model binder not to bind the field to the property of the model. By rendering the property using Html.HiddenFor have already achieved what you want in your rendered html. You can include a second parameter in your controller action as int OrderId and the model binder will bind the value on to that variable

A rogue user may still be able to edit OrderId. One way to guard it against such action is to encrypt OrderId and use the encrypted value in the model and subsequently on the page. Then once the postback happens, you will decrypt the encrypted OrderId. Encryption and decryption could be encapsulated in to the model itself

@TomerW, if I understood your question correctly, your core issue is that a rogue user can change the value of OrderId at the client side, My suggestion is not to render OrderId in its bare form, but encrypt it at the server side using a key only known at the server. You should render the encrypted value in HTML as a hidden filed. A rogue user may still attempt to change the associated value, but decryption will fail and you will know that someone has tried to fiddle with your value. Following is a stub implementation,

public class ChangeOrderDetailModel
{
    [ReadOnly(true)] /*You are instructing the model binder not to bind this value*/
    public int OrderId { get; set; }

    private string _OrderIdEnc;
    public string OrderIdEnc
    {
        /*Encryp*/
        get
        {
            return Encrypt(OrderId);
        }

        set
        {
            _OrderIdEnc = value;
        }
    }

    public void DecryptPayload()
    {
        /* Decrypt, and this will fail is someone has edited the value */
        OrderId = Decrypt(_OrderIdEnc);
    }
}

In your view model, use @Html.HiddenFor(o => o. OrderIdEnc). You can use standard windows crypto to do the encryption and decryption.

To be extremely safe, you can use a different key for each req/response session. This will prevent a more advanced rogue user from replacing OrderIdEnc with an older version.

I am sure that there may be other solutions, but above is a pattern that I have used many times and has worked

Cheers

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top