自定义 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
才能使其正常工作。
好吧,是的,现在是 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
才能使其正常工作。