简体中文

HTML、chmod、容器和 cron

四个实用程序背后的推理:为什么 HTML 编辑器需要白名单和沙箱、为什么 chmod 字符串中的大写 S 很重要、docker run 命令无法在 compose 中表达的内容,以及捕获所有人的两个 cron 规则。

HTML 编辑器:白名单,而不是过滤器

编辑器生成 HTML,而来自文本框的 HTML 是最古老的注入向量。这里混淆了两个不同的问题,因此值得将它们分开。第一个是“这个编辑器是否会被欺骗发出在显示它的页面中运行代码的标记?”第二个问题是“这是一种从不受信任的来源清除恶意 HTML 的安全方法吗?”该工具对第一个问题的回答是“是”,对第二个问题的回答是“否”,并且它在面板上如此说明,而不是让您做出其他假设。

该机制是允许名单。允许使用元素列表;所有其他元素都被展开,因此它的文本会保留下来,而它的标签不会。每个元素允许有一个属性列表;其他所有内容都被删除,这使得每个事件处理程序都变得不可能,而不仅仅是被阻止。属性名称在该测试之前是小写的,因此 oNeRrOr 和 ONERROR 与 onerror 是相同的拒绝名称。 HTML 解析器将其内容视为原始文本(脚本、样式、文本区域、iframe、标题)的元素与其内容一起删除,因为展开它们会将脚本源作为标记粘贴到文档中。

链接地址有自己的检查。在读取其方案之前,该值将被实体解码并删除空格和控制字符,因为这是浏览器在导航时所做的操作: javascript:alert(1) 和 jav ascript:alert(1) 都到达相同的位置。只有 http、https、mailto、tel、ftp 和相关地址仍然存在。该工具无法解析的字符引用(: 是典型的)会导致整个地址被拒绝而不是通过,因为比浏览器理解的输入内容少的过滤器是一个有漏洞的过滤器。

没有图像按钮,并且 img 不在允许列表中。允许的图像标签是来自文档结束位置的出站请求,以及 onerror 表面。对于一个创作散文的编辑来说,这也不值得。

不依赖于任何一个完美的防御就是预览。它在具有沙箱属性的 iframe 中呈现,该沙箱属性根本不授予任何内容 — 没有脚本、没有表单、没有同源访问。如果有效负载在允许列表中幸存下来,浏览器仍然会拒绝在那里执行它。这是一种结构性保证,而不是对我们代码的承诺。

诚实的限制:这是一个基于字符串的清理器,而不是一个完整的 HTML5 解析器。解析器差异(浏览器构建与此标记器不同的树的输入)是以这种方式构建的每个消毒器的已知弱点。对于输出,您可以在这个编辑器中自己生成,这很好。要清理来自陌生人的 HTML,请使用在您控制的服务器上针对真实解析器运行的清理程序。

chmod:大写字母是整个消息

Unix 文件模式有 12 位:所有者、组和其他各三个权限位,加上 setuid、setgid 和粘性位。八进制形式是直接读取这些位,这就是为什么 4 + 2 + 1 = 7 意味着读取、写入和执行。

ls 打印的符号形式是特殊位变得有趣的地方,因为它们没有自己的列。 setuid 替换所有者执行字符,setgid 替换组执行字符,sticky 替换其他执行字符。当底层执行位也被设置时,该字母为小写;当未设置时,该字母为大写。

所以 4755 是 rwsr-xr-x — 一个可以执行的 setuid 程序 — 而 4644 是 rwSr--r--,一个没人可以运行的 setuid 文件。大写的 S 是系统告诉您该钻头是惰性的,这几乎总是一个错误而不是一个选择。这同样适用于 1644,它显示 rw-r--r-T:常规文件上的粘性位,其中其他执行位是清除的,在现代内核上它完全不执行任何操作。

还有两个区别值得澄清。 ls 打印的九个字符的字符串不是 chmod 所采用的参数:chmod 需要一个赋值列表,例如 u=rwx,g=rx,o=rx,u+s。同样的位在目录上和在文件上意味着不同的东西——执行意味着“可以进入和遍历”,setgid意味着“新文件继承这个组”,而粘性位意味着“任何人都可以创建,只有所有者可以删除”,这就是 /tmp 是 1777 的原因。

docker run to compose:解析,以及不转换的内容

转换器使用为此工具编写的报价感知标记器来拆分命令。没有任何内容被执行、评估或传递给 shell。包含反引号、$(...) 或分号的命令将被读取为文字字符,因为该工具对您的输入所做的唯一操作就是读取它。

大多数标志都清晰地映射:端口、卷、环境、标签、重新启动策略、功能、运行状况检查、资源限制、DNS 和额外主机都具有具有相同含义的组合键。命名卷和用户定义的网络需要顶级声明以及服务引用,因此输出带有一个 - 在网络上使用 external: true ,因为网络 docker run 可以加入已经存在的网络。

有些标志没有 compose 等效项,这就是转换器通常会悄悄失败的地方。 --rm 不是服务属性:撰写服务退出时不会被删除。 -d 描述您如何调用 CLI,而不是服务是什么。 --link 是遗留的,--mount 需要一个长格式,这个工具不写,--gpus 取决于您的驱动程序。其中每一个都会产生一个命名警告而不是消失。未知标志也会产生警告,并被视为没有任何价值,因为猜测它有一个会将您的图像名称变成一个参数并产生一个肯定错误的文件。

输出不包含顶级版本:key。 Compose v2 会忽略它,当前版本会对此发出警告;自从 Compose 规范取代了旧的文件格式版本以来,它已经过时了。

引用不是装饰性的。不带引号的 8080:80 形式的端口映射被 YAML 1.1 解析器读取为数字,yes、no、on 和 off 是同一方言中的布尔值。任何可能被误读的内容都会被引用;任何以字符串形式清晰读取的内容都会被保留,因此文件保持可读。

Cron:两条适用于所有人的规则

首先是日规。当月份和星期几都设置为 * 以外的值时,cron 会在其中一个匹配时运行作业,而不是在两者都匹配时运行作业。所以 0 0 13 * 5 是“13号午夜,每周五午夜”,大约一个月五次,而不是“13号星期五”,每年一次或两次。每当两个字段都受到限制时,生成器就会发出警告,并且它所写的句子是“或”而不是“和”。

第二个是时区。 Cron 使用它运行的机器的区域,通常是服务器上的 UTC,而几乎从来不是编写 crontab 的人的区域。因此,下次运行预览会询问要使用哪个区域,而不是假设您的区域。时间是按照该区域的挂钟时间计算的,因此日常工作在夏令时变化期间会保持相同的当地时间,而不是漂移一个小时——而且每年春天跳过的一小时中不存在的当地时间会被排除在列表之外,因为那时 cron 也不会运行。

语法本身很小:一个星号、一个数字、一个范围 a-b、一个列表 a、b、c、一个步骤 */n 或 a-b/n,以及月份和日期名称 JAN-DEC 和 SUN-SAT。 0 和 7 均指星期日。带步长的裸值,例如分钟字段中的5/15,表示“从5到范围末尾,每15”,即分钟5、20、35和50。

验证是有目的的严格的。 60 * * * * 被拒绝,因为分钟停止于 59; * * * * 8 被拒绝,因为日期字段停在 7 处; */0 * * * * 被拒绝,因为零步不匹配任何内容。六个字段通常意味着 Quartz 或 systemd 表达式的第一个字段是秒,因此错误表明这一点而不仅仅是计数。语法上有效但永远无法运行的时间表 — 0 0 30 2 * 要求 2 月 30 日 — 会被接受并标记,因为拒绝它是错误的,保持沉默会更糟。

你粘贴的内容会发生什么

  • 每个转换、哈希、解码和差异都在您的浏览器选项卡中运行。不会在服务器上上传、记录或存储任何输入,因为页面加载后就不再涉及服务器。
  • 哈希值来自浏览器自己的 Web Crypto 实现,UUID 来自其加密安全随机生成器。两者都不涉及网络调用。
  • 您键入的任何内容都不会写入本地存储或 cookie。重新加载页面会丢弃它;关闭选项卡将丢弃它。
  • 站点范围的分析仅在配置的规范生产主机上运行,并在隐私政策中披露;本地和预览主机拒绝它。粘贴的值、令牌、URL 和文件内容不包括在 ToolAcre 自己的分析事件中。当前配置中禁用广告。
  • 也就是说:JWT 或 API 密钥是实时凭证。安全的习惯是永远不要将其粘贴到不是您编写的网页中,无论其声明多么可信 - 包括这个。

问题

我可以将恶意 HTML 粘贴到编辑器中来清理它吗?

您可以粘贴它,但不会执行任何操作:粘贴处理程序会在插入任何内容之前清理剪贴板有效负载,并且预览是一个没有允许脚本的沙盒 iframe。但请勿将结果用作不受信任输入的安全控制。这是一个基于字符串的允许列表,用于一个编辑器自己的输出,而不是通用的 XSS 过滤器,并且浏览器的解析器可以到达与像这样的标记器不同的树。对于不受信任的内容,请使用真正的 HTML5 解析器在服务器上进行清理。

为什么编辑要删除我的图片和表格?

因为他们不在许可名单上。图像是出站请求和错误表面;表格根本不属于该编辑器的用途。它们的文本内容会保留下来,而标签则不会。这是允许名单的工作,而不是错误——但这确实意味着这不是编辑复杂的现有文档的正确工具。

为什么 chmod 4644 显示大写的 S?

因为 setuid 已设置,但所有者执行位未设置。大写字母意味着特殊位没有任何作用:它是一个无法执行的 setuid 文件。小写 s 表示两个位均已设置。同样的规则为您提供了 S 代表 setgid 和 T 代表粘性位,而将其倒退是模式计算器中最常见的错误。

docker 转换器是否运行我的命令?

不,也不可能。该命令由一个只理解引用的分词器分割。没有 eval、没有 shell、没有子进程——页面无法启动它们。您粘贴的所有内容都会保留在选项卡中。

为什么转换器会发出警告而不是仅仅丢弃它无法处理的标志?

因为一个默默地执行比它来自的命令少的撰写文件比根本没有输出更糟糕:你会在生产中发现。每个未代表的标志都会被命名,并说明如何处理它。如果您没有看到任何警告,则没有任何损失。

为什么下一个 cron 运行与我的服务器运行的不同?

几乎总是时区。 Cron 使用运行它的机器的区域;预览使用您在下拉列表中选择的区域。将其设置为您服务器的区域(通常是 UTC),他们应该同意。另一个候选者是日期规则:如果同时设置了每月的某一天和每周的某一天,则 cron 会在其中任意一个上运行,这比大多数人预期的要频繁。

局限性

  • HTML 清理器是该编辑器自己的输出的允许列表,作为字符串标记器而不是完整的 HTML5 解析器实现。它不是通用 XSS 过滤器,不得用作过滤器。
  • 编辑器没有图像、表格、颜色或字体控件,也无法添加它们:允许列表之外的所有内容都将被删除。
  • 编辑界面使用 document.execCommand,它已被弃用并且没有实现替代。浏览器仍然支持它;它们之间的行为略有不同,尤其是在列表嵌套方面。
  • chmod 计算器仅涵盖十二个权限位。访问控制列表、扩展属性、SELinux 上下文、umask 算术和 Windows ACL 均超出范围。
  • docker 转换器将单个 docker run 命令转换为单个服务。它不读取 Dockerfiles,不解析镜像,并且无法表达 --mount、--gpus、--device、--link 或 --volumes-from;其中每一个都会产生一个命名警告。
  • 转换器无法识别的标志将被视为无值。如果这样的标志确实取了一个,则该值将被误读 - 警告是这样说的,删除该标志就是修复方法。
  • cron 生成器仅读取五字段 crontab 格式。六字段 Quartz 和 systemd 表达式、@reboot 以及非标准 L、W、# 和 ?操作员被拒绝而不是被猜测。
  • 下次运行时间来自浏览器自己的时区数据库,通过 Intl。它们是预览,而不是保证:运行 cron 的机器可能有不同的区域、不同的数据库版本,或者在时间到来时未运行的守护进程。