⚠️ 这是一个非官方翻译网站,与 ImageMagick Studio LLC 无关。准确信息请参阅原文(https://imagemagick.org/security-policy/)

安全策略

安全策略 • 安全策略示例 • 像素缓存同步策略 • 零配置安全策略 • 其他安全注意事项

在使用 ImageMagick 之前,强烈建议先建立一套适合本地环境的安全策略。ImageMagick 的安全模型是「除非被拒绝,否则全部允许」,并且最后匹配的策略优先生效。添加新规则时请务必小心:任何后置的策略都可能覆盖前面的 deny 或 allow。请将宽泛的 deny 规则放在前面,随后再加上具体的例外,并检查顺序以避免意外授权。

ImageMagick 在默认情况下是有意开放的,这一设计选择反映了它主要用于受控环境,例如 Docker 容器或其他沙箱化的部署。

ImageMagick 是一款用于操作图像的工具。它提供了多种功能与能力,但安全性与便利性之间往往存在权衡。为确保最佳安全性,你可以将 ImageMagick 限制为只读写 GIF、JPEG、PNG 等 web 安全图像格式。或者,你也可以根据本地环境或组织策略的需求自定义安全策略。该策略可以包含诸如内存使用上限、允许读写的路径、序列中图像数量的上限、工作流的最大运行时间、允许用于图像像素的磁盘空间、用于远程连接的密码口令,以及哪些 coder 被允许或拒绝等细节。通过自定义安全策略,你可以帮助保护环境,确保 ImageMagick 成为本地系统中负责任的一员,例如防止因处理大图而导致系统过载。

为防止潜在的有害情况,对 ImageMagick 的资源使用设置限制非常重要。例如,如果你不慎从互联网下载了一张被精心构造、用于生成超大图像(例如 20000×20000 像素)的图片,ImageMagick 可能会尝试分配所需的资源(如内存和磁盘空间),而你的系统可能会拒绝该请求或导致程序退出。或者,你的计算机可能会暂时变慢或无响应,又或者 ImageMagick 被迫中止。为避免此类情况,你可以在 policy.xml 配置文件中设置限制。

请记住,对一种环境而言合理的设置,对另一种环境可能并不适用。例如,你可能在安全的环境中对 ImageMagick 进行了沙箱隔离,而别人可能用它在公开可访问的网站上处理图像。或者,ImageMagick 运行在内存充裕的主机上,而另一个实例运行在资源受限的设备上。对内存充裕的主机来说,允许处理大图像也许是合理的,但对资源受限的设备则未必。如果你在公开网站上使用 ImageMagick,可能希望通过禁用 MVG 或 HTTPS 等特定 coder 来提高安全性。

为帮助你上手,自 7.1.1-16 版本起,ImageMagick 提供了可在安装时选择的安全策略。可从以下选项中选择:

open
ImageMagick 安装的默认策略是 open 安全策略。该策略适用于受防火墙保护的环境或 Docker 容器内等安全设置中的使用场景。在此框架下,ImageMagick 可以广泛访问资源与功能。该策略为图像操作提供了便利而灵活的选项。但需要注意,在监管较松的条件下它可能带来安全漏洞。因此,组织应根据自身的用例与安全要求,充分评估 open 策略的适用性。
limited
limited 安全策略的主要目标是在便利性与安全性之间找到折中点。该策略会停用可能存在危险的功能,例如 SVG 或 HTTP 等特定 coder。此外,它还对内存、存储、处理时长等资源的使用设置了若干约束(均可调整)。在需要降低处理可能恶意或高负载图像所带来潜在威胁、同时又要保留常见图像格式所必需的基本能力的场景中,该策略颇具优势。
secure
这套严格的安全策略优先实施严密的控制与受限的资源利用,以在使用 ImageMagick 时建立一个高度安全的环境。它会停用可能存在危险的功能,包括 SVG 或 HTTP 等特定 coder。该策略鼓励对安全措施进行定制,以契合本地环境的要求与组织的准则。此协议涵盖明确的细节,例如对内存消耗的限制、获准读写的路径、图像序列的上限、工作流的最长可允许时间、为图像数据分配的磁盘空间,甚至还有用于远程连接的非公开密码口令。通过采用这套稳健的策略,组织可以提升整体安全态势并缓解潜在的脆弱性。
websafe
这套为 web 安全用途设计的安全协议,聚焦于 ImageMagick 应用在网站等公开可访问场景的情形。它会停用读取或写入 GIF、JPEG、PNG 等 web 安全格式之外任何图像格式的能力。此外,该策略还禁止执行图像滤镜以及间接读取,从而阻止潜在的安全破坏。通过实施这些限制,websafe 策略强化了对公开可访问系统的保护,降低了 ImageMagick 的能力被用于潜在攻击的风险。

在 Linux 下,使用 configure 脚本的选项 --with-security-policy={open, limited, secure, websafe} 来选择策略。在 Windows 下,运行 configure 应用时会提示选项。

我们建议你审查 policy.xml 配置文件中的每一条规则。请根据组织的要求调整参数。你可以根据安全需求修改允许的图像格式、设置特定路径,并限制某些操作。请记住,自定义安全策略是在功能性与安全性之间的微妙平衡。过于严格的策略可能会妨碍正当的图像处理任务,而过于宽松的策略则可能引入脆弱性。

安全策略示例

下面是一个安全策略示例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policymap [
<!ELEMENT policymap (policy)*>
<!ATTLIST policymap xmlns CDATA #FIXED "">
<!ELEMENT policy EMPTY>
<!ATTLIST policy xmlns CDATA #FIXED "">
<!ATTLIST policy domain NMTOKEN #REQUIRED>
<!ATTLIST policy name NMTOKEN #IMPLIED>
<!ATTLIST policy pattern CDATA #IMPLIED>
<!ATTLIST policy rights NMTOKEN #IMPLIED>
<!ATTLIST policy stealth NMTOKEN #IMPLIED>
<!ATTLIST policy value CDATA #IMPLIED>
]>
<policymap>
  <!-- Set maximum parallel threads. -->
  <policy domain="resource" name="thread" value="2"/>
  <policy domain="resource" name="time" value="60"/>
  <policy domain="resource" name="file" value="768"/>
  <policy domain="resource" name="memory" value="256MiB"/>
  <policy domain="resource" name="map" value="512MiB"/>
  <policy domain="resource" name="area" value="16KP"/>
  <policy domain="resource" name="disk" value="1GiB"/>
  <policy domain="resource" name="list-length" value="16"/>
  <policy domain="resource" name="width" value="4KP"/>
  <policy domain="resource" name="height" value="4KP"/>
  <policy domain="resource" name="throttle" value="2"/>
  <policy domain="resource" name="dynamic-throttle" value="false"/>
  <policy domain="cache" name="memory-map" value="anonymous"/>
  <policy domain="cache" name="synchronize" value="true"/>
  <policy domain="delegate" rights="none" pattern="*"/>
  <policy domain="filter" rights="none" pattern="*"/>
  <policy domain="path" rights="none" pattern="-"/>
  <policy domain="path" rights="none" pattern="fd:*"/>
  <policy domain="path" rights="none" pattern="/etc/*"/>
  <policy domain="path" rights="none" pattern="*../*"/>
  <policy domain="path" rights="none" pattern="@*"/>
  <policy domain="module" rights="none" pattern="*" />
  <policy domain="module" rights="read | write" pattern="{GIF,JPEG,PNG,WEBP}" />
  <policy domain="system" name="shred" value="1"/>
  <policy domain="system" name="memory-map" value="anonymous"/>
  <policy domain="system" name="max-memory-request" value="256MiB"/>
  <policy domain="system" name="symlink" rights="none" pattern="follow"/>
</policymap>

为防止在同时处理多个会话时,某个会话耗尽全部可用内存,本策略会将大图像缓存到磁盘。如果图像超过像素缓存的磁盘上限,程序将退出。此外,还设置了时间限制,以防止任何处理任务运行过久。如果图像的宽度或高度超过 8192 像素,或者图像序列超过 32 帧,处理将停止并抛出异常。

自 ImageMagick 7.0.1-8 起,你可以阻止使用任意外部委托,或所有外部委托(将 pattern 设为 "*")。在此之前的版本中,你可以使用 coder 域,将 rights 设为 none,并将 glob 模式设为 HTTPS,以阻止外部委托的使用。此外,用户还会被禁止执行图像滤镜与进行间接读取。例如,如果你想从文件中读取文本(例如 caption:@myCaption.txt),就需要禁用此 path 策略。

在 ImageMagick 7.1.1-16 之前,策略的 glob 模式区分大小写。要获得预期行为,coder 和 module 必须使用大写(例如使用 "EPS" 而非 "eps"),或使用诸如 [Pp][Nn][Gg] 这样不区分大小写的模式。

例如,限制 HTTPS coder 后,你可以预期得到如下结果:

$ magick ../static/img/wizard.png wizard.jpg
convert: attempt to perform an operation not allowed by the security policy `HTTPS'
convert: no images defined `wizard.jpg'

自 ImageMagick 7.0.4-7 版本起,除少数经过验证的 web 安全图像类型外,你可以便捷地拒绝对所有外部委托和 coder 的访问。例如:

<policy domain="delegate" rights="none" pattern="*" />
<policy domain="module" rights="none" pattern="*" />
<policy domain="module" rights="read | write" pattern="{GIF,JPEG,PNG,WEBP}" />

module 策略针对读写两方面整体启用或禁用某个模块。若只想控制某种图像格式的读取或写入,请改用 coder 策略。例如,我们仅禁用少数几种 PostScript 相关格式的读取,而仍然允许写入:

<policy domain="coder" rights="write" pattern="{PDF,PS,PS2,PS3,XPS}" />

自 ImageMagick 7.0.7-0 起,你可以使用匿名内存映射而非堆来分配像素缓存和一些内部缓冲区。其结果是像素被初始化为零,会带来轻微的性能损失。你还可以在特定内存缓冲区(需要 7.1.0-38 版本)和临时文件被释放或删除之前打乱其内容。shred 值是用随机数据替换内容的次数。例如:

<policy domain="system" name="memory-map" value="anonymous"/>
<policy domain="cache" name="memory-map" value="anonymous"/>
<policy domain="system" name="shred" value="1"/>

出于性能考虑,第一遍很快,会按需重复随机序列来覆盖缓冲区或文件的内容。后续各遍会慢一个数量级,但会为缓冲区或文件的整个长度生成具有密码学强度的随机字节。

某些图像处理算法(例如小波变换)在完成时可能会消耗大量内存。ImageMagick 为这些大型资源请求维护着一个独立的内存池,并自 7.0.6-1 起允许你设置最大请求上限。如果超过该上限,分配将改为在磁盘上进行内存映射。这里我们通过策略来限制最大内存请求:

<policy domain="system" name="max-memory-request" value="256MiB"/>

自 ImageMagick 7.0.4-23 版本起,你可以限制序列中图像的最大数量。例如,要将图像序列限制为最多 64 帧,使用:

<policy domain="resource" name="list-length" value="64"/>

注意,策略中的数值为浮点数,可带可选的 SI 前缀(例如 10MiB)。

有关资源限制和策略配置文件的更多细节,请阅读 ResourcesArchitecture

自 ImageMagick 7.0.6-0 起,你可以通过 SetMagickSecurityPolicy()(MagickCore)或 MagickSetSecurityPolicy()(MagickWand)以编程方式设置 ImageMagick 的安全策略。

自 ImageMagick 7.0.8-11 版本起,你可以设置 module 安全策略。例如,要阻止 PostScript 或 PDF 解析,使用:

<policy domain="module" rights="none" pattern="{ps,pdf,xps}/>

自 ImageMagick 7.0-10-52 版本起,你可以设置 font 策略。指定一个 Unicode 字体的路径,当用户未指定字体偏好时,ImageMagick 会默认使用它:

<policy domain="system" name="font" value="/usr/share/fonts/arial-unicode.ttf"/>

注意,在文件路径的 glob 模式中,使用反斜杠(\)来转义那些原本会被解释为特殊字符的字符。例如:

<policy domain="path" rights="none" pattern="c:\\\\*"/>

你可以用以下命令验证你的策略更改是否已生效:

$ magick identify -list policy
Path: ImageMagick-7/policy.xml
  Policy: Cache
    name: memory-map
    value: anonymous
  Policy: Cache
    name: synchronize
    value: true
  Policy: Resource
    name: list-length
    value: 32
  Policy: Resource
    name: time
    value: 120
  Policy: Resource
    name: thread
    value: 2
  Policy: Resource
    name: file
    value: 768
  Policy: Resource
    name: disk
    value: 1GiB
  Policy: Resource
    name: map
    value: 512MiB
  Policy: Resource
    name: memory
    value: 256MiB
  Policy: Resource
    name: area
    value: 16KP
  Policy: Resource
    name: height
    value: 8KP
  Policy: Resource
    name: width
    value: 8KP
  Policy: Resource
    name: temporary-path
    value: /opt/tmp
  Policy: Module
    rights: Write
    pattern: {HTTP,HTTPS,MVG,PS,PDF}
  Policy: Filter
    rights: None
    pattern: *
  Policy: Path
    rights: None
    pattern: @*
  Policy: System
    name: font
    value: ImageMagick-7/arial-unicode.ttf

Path: [built-in]
  Policy: Undefined
    rights: None

注意,由于 stealth 属性,共享密钥的策略不会出现在列表中。

Doyensec 提供了一款策略评估工具,可以协助你设计与审计安全策略。该工具位于 imagemagick-secevaluator.doyensec.com

像素缓存同步策略

在将图像像素写入磁盘时,ImageMagick 会首先预分配磁盘文件,这比用零完全填充文件更快。为进一步提升性能,该文件会在磁盘上被内存映射。这可以带来最高 5 倍的性能提升,但存在一种可能:磁盘文件在被填充时空闲空间耗尽,导致操作系统(OS)抛出 SIGBUS 信号,从而阻止 ImageMagick 继续运行。为防止发生 SIGBUS 信号,使用以下安全策略:

<policy domain="cache" name="synchronize" value="True"/>

设为 True 可确保所有图像数据被完全刷新并同步到磁盘。虽然存在性能损失,但其好处包括:在系统崩溃时能够保证得到一个有效的图像文件,以及在用于图像像素缓存的磁盘空间不足时能够及早报告。

零配置安全策略

ImageMagick 的零配置构建不允许使用外部配置文件。要定义你的安全策略,必须改为编辑 MagickCore/policy-private.h 源模块,添加你的策略语句,然后构建 ImageMagick 发行版。下面是一个零配置安全策略示例:

static const char
  *ZeroConfigurationPolicy = \
"<policymap> \
  <policy domain=\"module\" rights=\"none\" pattern=\"MVG\"/> \
</policymap>";

其他安全注意事项

如果你在 ImageMagick 中发现了漏洞,请首先判断该漏洞是否可以通过安全策略来缓解。ImageMagick 默认是开放的。请使用安全策略添加约束,以满足本地安全治理的要求。如果你确信安全策略无法应对该漏洞,请将该漏洞作为安全公告提交。大多数漏洞会在 48 小时内得到审查与解决。

有几种方法可以让 ImageMagick 更安全:

  1. 使用 web 安全图像格式:将 ImageMagick 限制为只读写 GIF、JPEG、PNG 等 web 安全图像格式有助于提高安全性。
  2. 自定义安全策略:你可以根据本地环境或组织策略的需求自定义安全策略。该策略可以涵盖诸如内存使用、允许读写的路径、序列中允许的图像数量、工作流可运行的最长时间、允许用于图像像素的磁盘空间、用于远程连接的密码口令,以及哪些 coder 被允许或拒绝等方面。
  3. 对资源使用设置限制:你可以对内存使用、磁盘空间、工作流运行时间等资源设置限制,以防止潜在的有害情况。
  4. 使用沙箱:沙箱是一种安全技术,可让你在受限环境中运行程序,以防止其访问敏感信息或对系统进行更改。
  5. 禁用可能存在危险的 coder:如果你在公开网站上使用 ImageMagick,可能希望通过禁用 MVG 或 HTTPS 等特定 coder 来提高安全性。
  6. 阻止执行图像滤镜与间接读取:你可以阻止用户执行图像滤镜和进行间接读取,以提高安全性。
  7. 使用最新版本的 ImageMagick:使用最新版本的 ImageMagick 很重要,可以利用最新的安全修复与更新。