【问题标题】:Upload custom templates in django在 Django 中上传自定义模板
【发布时间】:2016-07-09 03:37:21
【问题描述】:

我希望用户能够上传他们的自定义 html 模板,包括 css 样式以及 png 和 jpeg 图像。这些 html 文件应可通过 django 检索。这意味着他们可以以普通网页的形式查看生成的 html 内容。为了能够做到这一点,我(似乎还不知道更好的方法)必须在模板目录中上传 html 文件。

这是我目前的模型:

class StylesheetFile(models.Model):
    HTML = 'HTML'
    CSS  = 'CSS'
    JPEG = 'JPEG'
    PNG  = 'PNG'

    # Currently supported mimetypes
    MIMETYPE_CHOICES = (
        (HTML, 'text/html' ),
        (CSS , 'text/css'  ),
        (JPEG, 'image/jpeg'),
        (PNG , 'image/png' ),
    )

    mimetype = models.CharField(max_length=64, choices = MIMETYPE_CHOICES)
    company = models.ForeignKey(Company)
    file = models.FileField(upload_to=get_upload_path)

这是当前确定upload_path的函数:

def get_upload_path(instance, filename):
    if instance.mimetype == 'HTML':
        return os.path.join(
            settings.TEMPLATES[0]['DIRS'][1],
            instance.company.name,
            filename)
    if instance.mimetype == 'CSS':
        return os.path.join(
            "custom_css",
            instance.company.name,
            filename)
    if instance.mimetype == 'JPEG' or instance.mimetype == 'PNG':
        return os.path.join(
            "custom_img",
            instance.company.name,
            filename)

模板设置

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            '/home/ubuntu/app/templates/',
            '/home/ubuntu/app/custom_templates',
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

当我这样做时,css 样式、png 和 jpeg 文件会正确上传,但 html 文件不会。我收到以下错误:

The joined path (/home/ubuntu/app/custom_templates/FooCompany/factors.html) is located outside of the base path component (/home/ubuntu/app/static/media)

我可以做些什么来防止这个错误?是否有一些最佳实践方法来解决我的问题,或者我是否必须采取一些解决方法,例如将我的 TEMPLATE_DIRS 之一设置为/home/ubuntu/app/static/media/custom_templates。也许这甚至不是一种解决方法和合法做法..我不知道真的知道..非常感谢帮助!

【问题讨论】:

    标签: django django-templates


    【解决方案1】:

    您不能使用FileField 上传MEDIA_ROOT 之外的文件。这是一项重要的安全措施。

    您可以将TEMPLATE_DIRS 设置为MEDIA_ROOT 内部的某个值,这很可能会起作用,但这让我很难受。这基本上让用户能够为网站上的 any 页面覆盖 any 模板。

    您不必将这些模板保存为 HTML 文件即可将它们用作 Django 模板。您可以将它们保存在数据库中并直接从字符串呈现它们:

    from django.template import engines
    from django.http import HttpResponse
    
    # Get the template from database
    template_from_db = YourCustomTemplateModel.objects.get(name='homepage')
    template_string = template_from_db.content
    
    # Create a django Template object
    template = engines['django'].from_string(template_string)
    
    # Render the template to a string
    context = {'foo': 'bar'}
    page_content = template.render(context=context)
    
    # Send page to a the browser
    return HttpResponse(page_content)
    

    但是,您应该认真考虑这样做通常会带来的安全隐患。您真的对模板创建者能够在您的域上设置任意 JavaScript(想想 跨站点脚本 漏洞)感到满意吗?调用任意方法(或至少是没有任何参数的方法)并访问您在 context 字典中传递的对象的任意参数怎么样?

    【讨论】:

    • 首先非常感谢您的回答!我已经考虑过这个安全问题,但我的上级告诉我写一个函数来检查 javascript 并且不允许它(我希望这听起来很简单)。所以基本上只允许用户上传html css和jpg和png。根本没有javascript
    • 删除 JavaScript 并不容易。不是以一种聪明的攻击者无法绕过的安全方式。实际上这是一个非常困难的问题。
    • JS 不是唯一的问题。您可以在模板中执行查询并泛洪数据库连接或获取敏感数据。 {% for friend in user.friends %}{{ friend.password }} {{ friend.email }}{% endfor %}{% for a in user.friends %}{% for b in a.friends %}{% for c in b.friends %}{% endfor %}{% endfor %}{% endfor %}
    • 至于移除 JavaScript。例如,给定这个字符串:<scr<script></script>ipt>alert('attack!');</scr<script></script>ipt> 一个简单的实现会剥离 <script></script> 并最终得到 <script>alert('attack!');</sript>,它仍然是 JavaScript。像这样的技巧有很多不同的,其中大多数都比较微妙。除此之外,JavaScript 可以以多种不同的方式嵌入到页面中(想想可以放在任何标签上的onclickonhover 等属性)。更糟糕的是:即使声明格式错误,许多浏览器也会执行 JavaScript。
    • 如果您绝对必须这样做,您可以尝试使用the Mozilla Bleach library白名单 几个选定且安全的 HTML 标记和属性。列表中的所有内容都应删除。漂白剂会帮助你。为了减轻@AntoinePinsard 表达的担忧,您应该只将简单的内置类型(如字符串和数字(​​或这些类型的列表))传递给context 字典中的变量。不像你通常做的那样查询集或模型对象。即使在这之后,我仍然对整件事感到不安。
    猜你喜欢
    • 2023-03-15
    • 2016-04-09
    • 2015-01-20
    • 2015-11-06
    • 2013-09-29
    • 2017-02-20
    • 2012-03-05
    • 1970-01-01
    • 2019-04-03
    相关资源
    最近更新 更多