Customize web form script generation
Ok, yes, it's 2020 but don't laugh. I'm trying update some ASP.NET web forms. My goal is to lock them down, making them more secure by applying a more restrictive Content Security Policy (CSP). To that end, I'm using a nonce, rather than allowing unsafe-inline
for scripting.
For "simple" web forms, it's working fine. However, I hit a problem whenever there's an ASP control that results in a post back. When I look in the page source, I see stuff like this:
<script type="text/javascript">
//<![CDATA[
var theForm = document.forms['form1'];
if (!theForm) {
theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
and
<script type="text/javascript">
function previewFile() {
var preview = document.querySelector('#Body_Main_LogoImage');
var file = document.querySelector('#Body_Main_logoUpload').files[0];
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
}
if (file) {
reader.readAsDataURL(file);
} else {
preview.src = "";
}
}
</script>
This code is generated by some of the MS web form code, I believe. The problem is that neither of these script elements have a nonce, which I'd like to supply, so it is in violation of my CSP (which does not include unsafe-inline
). Is there anything I can override to customize this behaviour?
Solution 1:
Some of the offending code is defined in a private method (e.g. RenderPostBackScript
) inside the Page
class, which in turn is called by internal methods. So, overriding it the normal way isn't an option unless I replace a large bunch of code. As an alternative, I overrode CreateHtmlTextWriter
in my page:
protected override System.Web.UI.HtmlTextWriter CreateHtmlTextWriter(TextWriter tw)
{
return new HtmlTextWriter(tw, this);
}
and then in my HtmlWriter
class, I do this:
public override void Write(string s)
{
if (s != null && s.IndexOf("<script") > -1 && s.IndexOf("nonce") == -1 && s.IndexOf("src") == -1)
{
s = s.Replace("<script", "<script nonce=\"" + this._page.GetNonce() + "\"");
}
base.Write(s);
}
I used a similar approach in my HtmlTextWriter
for AddAttribute
to avoid inline javascript:
inside href
, which would required unsafe-inline
for script-src
(and preclude the use of a nonce).
public override void AddAttribute(HtmlTextWriterAttribute key, string value)
{
if (key == HtmlTextWriterAttribute.Href && value != null && value.IndexOf("javascript:") > -1)
{
base.AddAttribute(key, "#");
var newScript = value.Replace("javascript:", "");
newScript += "; return false;";
base.AddAttribute(HtmlTextWriterAttribute.Onclick, newScript);
}
else
{
base.AddAttribute(key, value);
}
}
Solution 2:
You could override __DoPostBack
and use your own function instead.
var __original= __doPostBack;
__doPostBack = myFunction();
some more ideas over here: How to intercept any postback in a page? - ASP.NET