如何安全地将html和js存入数据库?

问题描述 投票:0回答:2

我们有一个 ASP.NET Core 6 MVC 应用程序,它在 SQL 数据库中存储 html 和 JS 脚本,然后在页面加载时呈现该 html 模板并执行 js 脚本(是的,这是允许用户创建不同 HTML 的应用程序要求模板)。

我们使用ace编辑器来编辑html和js。

HtmlTemplate
Js
是两个隐藏字段,ace editor 在任何变化时将值设置为这两个字段。

<script type="text/javascript">
  $(function () {
     //HTML
     var _htmleditor = ace.edit("editor");
     var _template = $("#HtmlTemplate");
     configureHtmlTemplate();

     function configureHtmlTemplate() {
         //some more configuration goes here
        _htmleditor .getSession().on("change", function () {
            _template.val(_htmleditor .getSession().getValue());
        });

        _htmleditor.getSession().setValue(_template.val());
     }

    //JS
    var _jsEditor = ace.edit("jsEditor");
    var _js = $("#Js");
    configureJsTemplate();

    function configureJsTemplate() {    
         //some more configuration goes here       
        _jsEditor.getSession().on("change", function () {
            _js.val(_jsEditor.getSession().getValue());
        });
        _jsEditor.getSession().setValue(_js.val());
    }
 })

服务器端

SaveTemplate
操作方法将 html 和 Js 保存到数据库,然后一些其他用户操作调用
Render
方法:

    [HttpPost]
    [Route("items/{id}/templates")]
    public async Task<ActionResult> SaveTemplate([FromRoute(Name = "id")] int itemID, [FromForm] EditTemplateModel model)
    {
        await _templateService.SaveTemplate(new ItemTemplate()
        {
            Id = model.Id,
            HtmlTemplate = model.HtmlTemplate,
            Js = model.Js
        }
        
        return View(model);
    }
            
    [HttpGet]
    [Route("items/{id}/render")]
    public async Task<IActionResult> Render([FromRoute(Name = "id")] int itemID)
    {
        var template = await _templateService.GetByID(itemID)

        var model = new RenderModel()
        {
            ItemID = itemID,
            Html = template.HtmlTemplate,                
            Js = template.JS
        };

        return View(model);
    }
    

Render.cshtml

    @model RenderModel
    
    <form method="post" id="renderForm" asp-action="SaveStuff" asp-controller="ItemTemplates" asp-route-id="@Model.ItemID">
        @Html.Raw(Model.Html)           
        <button  id="btnTest" class="btn btn-primary mt-3" type="submit">Submit</button>
    </form>
    
    <script type="text/javascript">    
        @Html.Raw(Model.Js)
    </script>

没错,Checkmarks 报告说这对 XSS 攻击很重要,因为我们正在使用

@Html.Raw()

来自 Microsoft 在 Asp.NET Core 中防止 XSS

MVC 中使用的 Razor 引擎会自动对来自变量的所有输出进行编码,除非您非常努力地阻止它这样做。

但是在我的应用程序中,我必须在浏览器中呈现存储的 html,所以我使用

@Html.Raw()

普遍接受的做法是编码发生在输出点,编码值永远不应该存储在数据库中。

但是如果我在输出之前对模板进行编码,那么下面的代码将不会产生预期的结果。它不会显示粗体文本,而是呈现为

<b>Foo Bar</b>
这不是预期的。

@{
    var htmlStoredInDB = "<b>Foo Bar</b>";
    var untrustedInput = System.Text.Encodings.Web.HtmlEncoder.Default.Encode(htmlStoredInDB);
}

@Html.Raw(untrustedInput)

这里的解决方案是什么? .NET 6 中是否有可用的实用程序来在呈现之前清理 html 和 js?或任何其他更好的选择?

更新一

我在这里考虑两步走的方法(我仍然愿意接受任何其他建议)

  1. 在保存到数据库之前对 HTML 进行清理,以删除任何恶意代码。

  2. 在第 1 步中,清理仅适用于 HTML 模板,不适用于 JS 模板。很难区分坏 JS 和好 JS。沙盒技术可以将 HTML 和 JS 内容与主窗口隔离,并最大限度地减少爆炸半径。沙盒可能需要更多的工作和测试。我们现有的模板可能需要重构。 我注意到 JSFiddle 使用沙盒方法

asp.net-core asp.net-core-mvc .net-6.0 xss html-sanitizing
2个回答
0
投票

我已经通过关键词--.

搜索了这个问题

我发现官方文档有

HtmlEncoder 
JavaScriptEncoder
.

我还发现了这个优秀的 github repo(HtmlSanitizer)。


-1
投票

使用

@Html.Raw()
从数据库呈现 HTML 和 JS 代码被认为是不安全的,因为它会让您的应用程序对 XSS(跨站点脚本)攻击开放。

为了避免这些风险,我们可以使用一个库来在呈现到浏览器之前清理我们的 HTML 和 JS 代码。

推荐图书馆:

Microsoft.AspNetCore.WebUtilities.HtmlEncoder
.

如何使用 HTMLEncoder 的简单示例:

@{
    var htmlStoredInDB = "<b>Foo Bar</b>";
    var sanitizedHtml = Microsoft.AspNetCore.WebUtilities.HtmlEncoder.Default.Encode(htmlStoredInDB);
    var jsStoredInDB = "alert('Hello, world!');";
    var sanitizedJs = Microsoft.AspNetCore.WebUtilities.JavaScriptEncoder.Default.Encode(jsStoredInDB);
}

@Html.Raw(sanitizedHtml)
<script>
    @Html.Raw(sanitizedJs)
</script>

注意:以上代码仅用于防止 xss 攻击,它会将其生成为纯文本,不会以粗体返回“Foo Bar”,而是返回

"<b>Foo Bar</b>"

以防万一,如果您想避免 xss 攻击,并使用应用的标签呈现 html。您应该对 HTML 代码进行编码和清理。

使用的库(.Net 6 支持):

  • System.Text.Encodings.Web;(用于编码使用)

  • HtmlAgilityPack;(用于消毒)

例子:

using System.Text.Encodings.Web;
using HtmlAgilityPack;

public static class HtmlUtility
{
    public static string EncodeAndSanitizeHtml(string inputHtml)
    {
        var allowedTags = new[] { "b", "i", "u" };
        var doc = SanitizeHtml(inputHtml, allowedTags);
        var writer = new System.IO.StringWriter();
        doc.Save(writer);
        return HtmlEncoder.Default.Encode(writer.ToString());
    }
    
    private static HtmlDocument SanitizeHtml(string html, string[] allowedTags)
    {
        var doc = new HtmlDocument();
        doc.LoadHtml(html);

        foreach (var node in doc.DocumentNode.DescendantsAndSelf())
        {
            if (!allowedTags.Contains(node.Name))
            {
                node.Remove();
            }
        }

        return doc;
    }
}

调用上面的方法:

string inputHtml = "<html><head><title>Page title</title></head><body><h1>Hello world!</h1><b>happy</b></body></html>";
string outputHtml = HtmlUtility.EncodeAndSanitizeHtml(inputHtml);
Console.WriteLine(outputHtml); // Output: &lt;b&gt;happy&lt;/b&gt;

在输出中,标签编码如上,但在 HTML 上下文中呈现时,它将以粗体显示文本。

注意:以上步骤不适用于编码或消毒 JavaScript 代码。对于 JavaScript,建议使用特定的 JavaScript 消毒剂或安全工具,如 DOMPurify 库, 它专门用于清理和保护 JavaScript 代码 来自 XSS 攻击。

© www.soinside.com 2019 - 2024. All rights reserved.