UpdateFrom and Encodinghttp://forums.asp.net/t/1194407.aspx/1?UpdateFrom+and+EncodingTue, 25 Dec 2007 18:00:46 -050011944072060170http://forums.asp.net/p/1194407/2060170.aspx/1?UpdateFrom+and+EncodingUpdateFrom and Encoding <p>Hi, I installed MVCToolkit and played with tutorials. I tried to create some Product object (Linq To Sql) in an action method: But encoding for string values in Request.Form didn't happen and I successfully saved javascript code as product name :( </p> <pre class="prettyprint">[ControllerAction] public void CreateNew() { Product prod = new Product(); prod.UpdateFrom(Request.Form); northwind.AddProduct(prod); northwind.SubmitChanges(); ..... }</pre>What do I need to do to have encoding 2007-12-14T13:36:41-05:002060259http://forums.asp.net/p/1194407/2060259.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>If you need to apply custom logic to the data that's assigned, the current UpdateFrom() method might not be a good approach to you. There isn't a way to control programmatically any encoding or access restrictions (besides passing an array of property names).</p> <p>If would be nice if, in future, there was an extended version of UpdateFrom() that would take a delegate to call back some custom logic to handle each member.&nbsp; It could look like this:</p> <pre>// Defined by the framework<br>public class UpdateMemberData<br>{<br> public object Value { get; set; }<br> public bool AllowUpdate { get; set; }<br>}<br>public delegate void UpdateMemberDelegate(Object targetObject, MemberInfo targetMember, UpdateMemberData data);<br>public static void UpdateFrom(this T obj, NameValueCollection values, UpdateMemberDelegate callback) { ... }<br><br>// Called by the user<br>myObject.UpdateFrom(Request.Form, delegate(Object targetObject, MemberInfo targetMember, UpdateMemberData data) {<br> switch (targetMember.Name)<br> {<br> case &quot;SomeProperty&quot;:<br> case &quot;SomeOtherProperty&quot;:<br> data.Value = HttpUtility.HtmlEncode((string)data.Value);<br> break;<br> case &quot;UnprotectedProperty&quot;:<br> break; // Allow unescaped data<br> default:<br> data.AllowUpdate = false; // Block access to any other members<br> break;<br> }<br> data.AllowUpdate = false; <br>});<br></pre> <p>Not really sure how advantageous this is anyway, as some type-safety is lost. </p> 2007-12-14T14:20:29-05:002060343http://forums.asp.net/p/1194407/2060343.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>How&nbsp;the javascript getting into the form fields? </p> 2007-12-14T14:52:59-05:002060349http://forums.asp.net/p/1194407/2060349.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>I found an acceptable solution (for me :) ):</p> <p>In BindingHelpers.cs file of MVCToolkit solution I added some code to UpdateForm method (at line number&nbsp;100)...</p> <pre class="prettyprint">... string strValue = value as string; if (strValue != null) value = HttpUtility.HtmlEncode(strValue); ...</pre> 2007-12-14T14:56:46-05:002060355http://forums.asp.net/p/1194407/2060355.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p></p> <blockquote><span class="icon-blockquote"></span> <h4>slynch</h4> <p>How&nbsp;the javascript getting into the form fields? </p> <p></p> </blockquote> <p></p> <p>I just entered &lt;script&gt;alert('possible xss');&lt;/script&gt; into input field</p> 2007-12-14T14:58:49-05:002060476http://forums.asp.net/p/1194407/2060476.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>Sorry, what you ment was pretty obvious now that I think of it. </p> <p>You might want to consider adding something like this so it wont be replace if you update to the next drop of the MVCToolkit</p> <font color="#0000ff" size="1"> <p>namespace</font><font size="1"> System.Web.Mvc.BindingHelpers{<br> </font><font color="#0000ff" size="1">public</font><font size="1"> </font><font color="#0000ff" size="1">static</font><font size="1"> </font><font color="#0000ff" size="1">class</font><font size="1"> </font><font color="#2b91af" size="1">CustomBindingHelperExtentions</font><font size="1">{<br> </font><font color="#0000ff" size="1">&nbsp; public</font><font size="1"> </font><font color="#0000ff" size="1">static</font><font size="1"> </font><font color="#0000ff" size="1">void</font><font size="1"> UpdateFrom(</font><font color="#0000ff" size="1">this</font><font size="1"> </font><font color="#0000ff" size="1">object</font><font size="1"> obj, </font><font color="#2b91af" size="1">NameValueCollection</font><font size="1"> values, </font><font color="#2b91af" size="1">Expression</font><font size="1">&lt;</font><font color="#2b91af" size="1">Func</font><font size="1">&lt;</font><font color="#0000ff" size="1">string</font><font size="1">, </font><font color="#0000ff" size="1">string</font><font size="1">&gt;&gt; encoder, </font> <font color="#0000ff" size="1">params</font><font size="1"> </font><font color="#0000ff" size="1">string</font><font size="1">[] keys)<br> &nbsp; {<br> </font><font color="#2b91af" size="1">&nbsp;&nbsp;&nbsp; NameValueCollection</font><font size="1"> encodedValues = </font><font color="#0000ff" size="1">new</font><font size="1"> </font><font color="#2b91af" size="1">NameValueCollection</font><font size="1">();<br> </font><font color="#2b91af" size="1">&nbsp;&nbsp;&nbsp; Func</font><font size="1">&lt;</font><font color="#0000ff" size="1">string</font><font size="1">, </font><font color="#0000ff" size="1">string</font><font size="1">&gt; encodeFunc = encoder.Compile();<br> </font><font color="#0000ff" size="1">&nbsp;&nbsp;&nbsp; foreach</font><font size="1"> (</font><font color="#0000ff" size="1">string</font><font size="1"> key </font><font color="#0000ff" size="1">in</font><font size="1"> values.Keys)<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; encodedValues.Add(key, encodeFunc(values[key]));<br> </font><font color="#0000ff" size="1">&nbsp;&nbsp;&nbsp; if</font><font size="1"> (keys.Length &gt; 0)<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; obj.UpdateFrom(encodedValues, keys);<br> </font><font color="#0000ff" size="1">&nbsp;&nbsp;&nbsp; else<br> </font><font size="1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; obj.UpdateFrom(encodedValues);<br> &nbsp;&nbsp;&nbsp; }<br> &nbsp; }<br> }</font></p> <p><font size="1"><font size="2">And then call it like:</font></font></p> <p><font size="1"><font size="2">prod.UpdateFrom(Request.Form,c=&gt;HttpUtility.HtmlEndoce(c));<font size="1"></p> </font></font></font> 2007-12-14T15:50:28-05:002060628http://forums.asp.net/p/1194407/2060628.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>Thanks for the feedback - we're going to make two changes to the helpers in the next drop:</p> <p>1) Encoding will be ON by default</p> <p>2) There will be an override to turn it off (if you use an RTE for instance)</p> <p>The other alternative (as you've seen above) is to override what we're doing with your own method for now.</p> <p>I should have done it this way in the first place :).</p> 2007-12-14T17:11:06-05:002060661http://forums.asp.net/p/1194407/2060661.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>quick question, I'm a little confused, but why would want to by default HtmlEncode an input and stuff that into your DomainObject and ultimately into the database? shouldn't it be the other way around, you HtmlEncode it for displaying purpose, and store it as is?</p> 2007-12-14T17:25:28-05:002060665http://forums.asp.net/p/1194407/2060665.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>It can be either way - but the safest bet is &quot;protect inbound&quot; since you never know where that info will turn up again. For instance if you're object is a ProductReview and you forget to encode the output. It happens.</p> <p>Also - it's not a very expensive operation, but it is string manipulation and therefore has a cost to it. If you encode on every output it can add up and hurts scaling. </p> 2007-12-14T17:27:50-05:002060742http://forums.asp.net/p/1194407/2060742.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p></p> <blockquote><span class="icon-blockquote"></span> <h4>slynch</h4> <p>Sorry, what you ment was pretty obvious now that I think of it. </p> <p>You might want to consider adding something like this so it wont be replace if you update to the next drop of the MVCToolkit</p> <font color="#0000ff" size="1"> <p>namespace</font><font size="1"> System.Web.Mvc.BindingHelpers{<br> </font><font color="#0000ff" size="1">public</font><font size="1"> </font><font color="#0000ff" size="1">static</font><font size="1"> </font><font color="#0000ff" size="1">class</font><font size="1"> </font><font color="#2b91af" size="1">CustomBindingHelperExtentions</font><font size="1">{<br> </font><font color="#0000ff" size="1">&nbsp; public</font><font size="1"> </font><font color="#0000ff" size="1">static</font><font size="1"> </font><font color="#0000ff" size="1">void</font><font size="1"> UpdateFrom(</font><font color="#0000ff" size="1">this</font><font size="1"> </font><font color="#0000ff" size="1">object</font><font size="1"> obj, </font><font color="#2b91af" size="1">NameValueCollection</font><font size="1"> values, </font><font color="#2b91af" size="1">Expression</font><font size="1">&lt;</font><font color="#2b91af" size="1">Func</font><font size="1">&lt;</font><font color="#0000ff" size="1">string</font><font size="1">, </font><font color="#0000ff" size="1">string</font><font size="1">&gt;&gt; encoder, </font> <font color="#0000ff" size="1">params</font><font size="1"> </font><font color="#0000ff" size="1">string</font><font size="1">[] keys)<br> &nbsp; {<br> </font><font color="#2b91af" size="1">&nbsp;&nbsp;&nbsp; NameValueCollection</font><font size="1"> encodedValues = </font><font color="#0000ff" size="1">new</font><font size="1"> </font><font color="#2b91af" size="1">NameValueCollection</font><font size="1">();<br> </font><font color="#2b91af" size="1">&nbsp;&nbsp;&nbsp; Func</font><font size="1">&lt;</font><font color="#0000ff" size="1">string</font><font size="1">, </font><font color="#0000ff" size="1">string</font><font size="1">&gt; encodeFunc = encoder.Compile();<br> </font><font color="#0000ff" size="1">&nbsp;&nbsp;&nbsp; foreach</font><font size="1"> (</font><font color="#0000ff" size="1">string</font><font size="1"> key </font><font color="#0000ff" size="1">in</font><font size="1"> values.Keys)<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; encodedValues.Add(key, encodeFunc(values[key]));<br> </font><font color="#0000ff" size="1">&nbsp;&nbsp;&nbsp; if</font><font size="1"> (keys.Length &gt; 0)<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; obj.UpdateFrom(encodedValues, keys);<br> </font><font color="#0000ff" size="1">&nbsp;&nbsp;&nbsp; else<br> </font><font size="1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; obj.UpdateFrom(encodedValues);<br> &nbsp;&nbsp;&nbsp; }<br> &nbsp; }<br> }</font></p> <p><font size="1"><font size="2">And then call it like:</font></font></p> <p><font size="1"><font size="2">prod.UpdateFrom(Request.Form,c=&gt;HttpUtility.HtmlEndoce(c));<font size="1"></p> </font></font></font></blockquote> <p>Thank you, it's the best solution for now</p> 2007-12-14T18:08:23-05:002062326http://forums.asp.net/p/1194407/2062326.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>Rob, please tell me you're not serious about HTML-encoding all input by default. I appreciate that you're trying to protect people from their own ignorance or forgetfulness, but as shinakuma indicated, this causes more problems than it solves.<br> <br> [1] It's an inappropriate mix of technologies. HTML encoding is only a concern of displaying HTML - it has no place in a SQL database. It's ugly when querying, interferes with full-text indexing, and clashes with other applications that might be reading from the same DB. What about when I'm not outputting to HTML (e.g. when rendering to a plain-text email, WinForms app, or 3rd party system) - do I have to unescape it first? Yuck!<br> <br> [2] It leads to more serious security vulnerabilities. You say it's safer to &quot;protect inbound&quot;, but here the opposite is true. Remember that by saying &quot;we'll protect inbound&quot;, you're also saying &quot;you must not protect outbound&quot; (otherwise you'll double-escape and &amp; will render as &amp;amp;). So now we are forced to trust that all systems writing to the DB remember to encode all strings exactly once, and any single vulnerability spreads to all parts of the system because nothing protects outbound. &quot;Perimiter security&quot; is not safer when it actually prevents you from adding real security.<br> <br> [3] It's inconsistent with how decent ASP.NET controls work. Well-written controls take responsibility for HTML-encoding their own output, so pre-escaped strings would cause display problems.<br> <br> [4] It's inconsistent with how other aspects of the MVC framework work. You're not pre-escaping all values passed to IHttpRequest.Form, so myObject.Value = form['key'] would behave differently to myObject.UpdateFrom(form).<br> <br> If someone on my team encoded strings before putting them into the DB, then depended on that when rendering them later, I'd have to tell them off and ask them to change it. Please don't encourage this behaviour! <br> </p> 2007-12-16T17:59:00-05:002062404http://forums.asp.net/p/1194407/2062404.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>&#43;1Steve </p> 2007-12-16T20:16:33-05:002062432http://forums.asp.net/p/1194407/2062432.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>Um... maybe that was an excessive rant - I do really like the MVC framework so far! Good work [:)]<br> </p> 2007-12-16T20:54:04-05:002064688http://forums.asp.net/p/1194407/2064688.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>ScottGu and I talked a bit about this and HTMLEncoding a security concern so we have to take this into consideration when deciding how to deal with these things. </p> <p></p> <blockquote><span class="icon-blockquote"></span> <h4>SteveSanderson1</h4> It's an inappropriate mix of technologies. HTML encoding is only a concern of displaying HTML - it has no place in a SQL database. It's ugly when querying, interferes with full-text indexing, and clashes with other applications that might be reading from the same DB. </blockquote> <p></p> <p>In terms of it's &quot;place&quot; - I highly disagree. Anything that is being reported back to a web front end (usually a browser) should, at some level, be checked so that you don't inadvertantly sabotage your user. Database, flatfile, cache - the storage medium has nothing to do with this :). FullText indexing ignores anything in &lt;&gt;.</p> <p>One thing you can do here is to Encode on the way out - but again that's a perf thing you'd need to think about. I hear you though about the other readability issues, and we can have an override to turn it off.</p> <p></p> <blockquote><span class="icon-blockquote"></span> <h4>SteveSanderson1</h4> &quot;Perimiter security&quot; is not safer when it actually prevents you from adding real security.<br> </blockquote> <p></p> <p>Yep. Security comes at a cost at some level and I agree with you in principle here. However you're talking about a 1% issue at best (shared DB input) and many architects would completely cringe at sharing a DB with a web site for this very reason. However your point is valid and again - we'll provide an override so the decision to turn this off if you need.</p> <p></p> <blockquote><span class="icon-blockquote"></span> <h4>SteveSanderson1</h4> It's inconsistent with how other aspects of the MVC framework work.</blockquote> <p></p> <p>Hopefully not - but if we're not encoding properly we need to take a look at that.</p> <p>Ultimately it boils down to line of responsibility - should Microsoft, by default, disable security or should you, as the developer, disable it for yourself? I'm all for trying to find a better answer here - would another route be acceptable - something like &quot;UpdateFromEncode(Request.Form)&quot;? The thing is - and I'm going to stick to this - the decision to turn encoding off needs to be the developer's.</p> <p>--Iniviting ScottGu and DamienG to this thread - it's a good one and it's important.</p> 2007-12-17T23:02:33-05:002064699http://forums.asp.net/p/1194407/2064699.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>We are talking about Encoding not Decoding.... The name alone dictates the direction. <br> </p> <p>What if I am not even outputting html but some other format.&nbsp; Now I need to ensure that all my input is not encoded? </p> <p>On by default is just confusing.&nbsp; I would change the method names all together so it is explicit what is going on.&nbsp;</p> <p>&nbsp;</p> 2007-12-17T23:15:16-05:002064726http://forums.asp.net/p/1194407/2064726.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>WebForms by default validates the request for injection attacks, it does NOT however by default html encode everything&nbsp;to be&nbsp;passed along&nbsp;&quot;securely&quot;&nbsp;into your DB. It's unreasonable to assume that your data will be in a silo consumed only by your web frontend when dealing with enterprise applications. I don't want to have to worry about html decoding when I import these data into my warehouse or sync over to a legacy system, or like someone said output to a non-html format. That is just backwards. The default behavior should be you encode for display, not for storage.</p> 2007-12-17T23:42:47-05:002064731http://forums.asp.net/p/1194407/2064731.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>Any helper functions that output HTML should encode values using HttpUtility.HtmlEncode for literals and HttpUtility.HtmlAttributeEncode for attributes such as value on input tags.</p> <p>If users want to output unencoded HTML then let them do that themselves without a helper as it's not easy to deal with.&nbsp;</p> <p>Where you are bringing data back for processing through a form you don't need to do anything - the request variable will contain it unencoded.</p> <p>Definitely do not encode it going into the database - to do so would pollute your data with HTML encoding. If you thought having presentation and model logic separate was important then imagine what stuffing HTML into the database would mean. If you ever wanted to show it via another application such as a WinForm, Console or XML variant you'll have to do cross-conversion. It would also mean that you can no longer HTML encode the output or you would double encode it and actually start displaying &amp;lt; in text boxes.</p> 2007-12-17T23:48:45-05:002064774http://forums.asp.net/p/1194407/2064774.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>I have a new post up on my blog entitled <a href="http://damieng.com/blog/2007/12/18/5-signs-your-aspnet-application-may-be-vulnerable-to-html-injection"> 5 signs your ASP.NET application may be vulnerable to HTML injection</a> if anyone is interested in the subject (it affects WebForms and HtmlControls too).<br> </p> 2007-12-18T00:41:52-05:002065484http://forums.asp.net/p/1194407/2065484.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>Rob (and the others), thanks for giving this issue such careful consideration. I appreciate that you're trying to do the right thing by &quot;enabling security by default&quot;.&nbsp;</p> <p>Many arguments could be made, but for me the key thing is &quot;what kind of a future are you creating&quot;. As you're in the priviledged position of designing a Microsoft-endorsed framework, the mindset you take is going to influence countless web developers for many years to come (otherwise, this would just be a minor technicality and I wouldn't really care either way). If you proceed with the idea &quot;we'll encode the data inbound&quot;, you are not just perpetuating ignorance about encoding it outbound, you're actually *enforcing inaction*. It means that developers learn like monkeys they must *not* encode the data they send, because some black magic somewhere in the system does that and they have to trust it to avoid double-escaping. Do you think they are going to behave differently when working with different data sources? It just creates unpredictability, instead of the simple rule: &quot;escape any strings that you don't want to render as HTML&quot;.<br> </p> <p>In other words, it only enables an illusion of security, and ultimately causes a greater loss of security (as well as millions of wasted person-hours trying to remember which pieces of data are pre-encoded and which ones aren't). So yes, it does boil down to responsibility - responsibility for our future, and our children's future... ([&#43;o(])</p> <p>What I would ultimately like, though I appreciate this would turn a few things upside-down, would be to change the meaning of &lt;%= ... %&gt; on MVC ViewPages, so it escapes the strings you pass it. You would force developers to use more keystrokes when they want to avoid escaping (instead of fewer), maybe using &lt;%!= ... %&gt; or even &lt;%= RawHtml(...) %&gt;.<br> </p> <p></p> <blockquote><span class="icon-blockquote"></span> <h4>robconery</h4> However you're talking about a 1% issue at best (shared DB input) and many architects would completely cringe at sharing a DB</blockquote> <p></p> <p>Considering the other comments posted, the people who hang out on this forum are somewhat architecturally minded - sharing databases, legacy data storage, and interacting with external systems aren't 1% issues for us - it's what we do every day. Perhaps we're not representative of your wider customer base, but we are the opinion shapers.<br> </p> <p></p> <blockquote><span class="icon-blockquote"></span> <h4>robconery</h4> One thing you can do here is to Encode on the way out - but again that's a perf thing you'd need to think about</blockquote> <p></p> <p>Have you done any benchmarking of this? As a quick test, my humble desktop can HTML-encode 1.5 million 30-character strings per second (in which about every 5th character needs encoding), and about half of that processing time goes into allocating a new string on the heap. Compared to the cost of a database query, a few hundred encodings is completely insignificant, and if you're pushing your webserver that hard, I'd hope you're using output caching anyway.</p> <p></p> <blockquote><span class="icon-blockquote"></span> <h4>robconery</h4> UpdateFromEncode(Request.Form)</blockquote> <p></p> <p>Yeah, great! Or just, UpdateFrom(Request.Form, Encoding.HtmlEncodeAllFields), as long as the default is not to encode.<br> &nbsp;</p> 2007-12-18T08:46:02-05:002065543http://forums.asp.net/p/1194407/2065543.aspx/1?Re+UpdateFrom+and+EncodingRe: UpdateFrom and Encoding <p>HTML encoding is an output-only issue - there should NOT be any facility to encode data going into the database. 100%, no exceptions, not even as an option the developer can specify.<br> </p> <p>If you HTML encode data into the database you force web developers into writing unsafe code because if they do HTML encode now it will be double-encoded and will display as a mess of &amp;quot; etc. all over the screen/output/XML/RSS.</p> <p>Of course there are times when HTML is desired in the database - rich text might be one option - but that's a totally different game and in fact requires neither encoding or decoding which would actually break that. In those scenarios you require careful scrubbing to ensure only the tags you wanted in there get kept.<br> </p> <p>You effectively turn what was a simple rule - encode data into the output stream correctly - into a guessing game by doing this.<br> </p> 2007-12-18T09:21:57-05:00