自定义 Web 表单脚本生成

Customize web form script generation

好吧,是的,现在是 2020 年,但不要笑。我正在尝试更新一些 ASP.NET 网络表单。我的目标是锁定它们,通过应用更具限制性的内容安全策略 (CSP) 使它们更加安全。为此,我使用了随机数,而不是允许 unsafe-inline 用于脚本。

对于“简单”的 Web 表单,它工作正常。但是,每当有 ASP 控件导致返回 post 时,我就会遇到问题。当我查看页面源代码时,我看到这样的内容:

<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();
    }
}

<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>

我相信此代码是由某些 MS 网络表单代码生成的。问题是这些脚本元素都没有我想提供的随机数,因此它违反了我的 CSP(不包括 unsafe-inline)。有什么我可以覆盖来自定义此行为吗?

您可以覆盖 __DoPostBack 并改用您自己的函数。

var __original= __doPostBack;
__doPostBack = myFunction();

这里还有一些想法: How to intercept any postback in a page? - ASP.NET

一些有问题的代码是在 Page class 内部的私有方法(例如 RenderPostBackScript)中定义的,而这些代码又会被内部方法调用。因此,除非我替换一大堆代码,否则无法以正常方式覆盖它。作为替代方案,我在我的页面中覆盖了 CreateHtmlTextWriter

protected override System.Web.UI.HtmlTextWriter CreateHtmlTextWriter(TextWriter tw)
{
    return new HtmlTextWriter(tw, this);
}

然后在我的 HtmlWriter class 中,我这样做:

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);
}

我在 HtmlTextWriter 中为 AddAttribute 使用了类似的方法来避免在 href 中内联 javascript:,这需要 unsafe-inline 为 [=22] =](并排除使用随机数)。

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);
    }
}

如果您在 Chrome 中打开开发工具,您可能会看到类似 Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self'. Either the 'unsafe-inline' keyword, a hash ('sha256-2NqnatcPqy5jjBXalTpZyJMO/0fUaYUb3ePlviUP4II='), or a nonce ('nonce-...') is required to enable inline execution.

的消息

如果您仔细查看该消息,它会告诉您哈希值是什么:sha256-2NqnatcPqy5jjBXalTpZyJMO/0fUaYUb3ePlviUP4II=

所以如果你不想走随机数路线,你可以改为走散列路线并添加

Content-Security-Policy: script-src 'self' 'sha256-2NqnatcPqy5jjBXalTpZyJMO/0fUaYUb3ePlviUP4II=' 'unsafe-eval';

在某些情况下,您可能还必须添加 unsafe-eval 才能使其正常工作。