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

安全策略

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

ImageMagick 安全策略

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

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

安全总是要在防范潜在漏洞与把工作完成的实际需要之间取得平衡。在 ImageMagick 中,安全策略就是让你调节这一平衡的机制。它充当严格锁定与操作便利之间的控制点,让你决定在你的环境中允许哪些功能、coder 和操作。

精心设计的策略可以:

  • 限制或禁用高风险的 coder 和操作。
  • 约束资源使用,防止滥用。
  • 精确规定允许 ImageMagick 处理哪些类型的输入。
  • 让系统适应你的威胁模型,而不是强行套用一刀切的配置。

这种灵活性是有意为之的。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 配置文件中的每一条规则。请根据组织的要求调整参数。你可以根据安全需求修改允许的图像格式、设置特定路径,并限制某些操作。请记住,自定义安全策略是在功能性与安全性之间的微妙平衡。过于严格的策略可能会妨碍正当的图像处理任务,而过于宽松的策略则可能引入脆弱性。

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

安全策略示例

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

<?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>
]>
<!--
  Creating a security policy that fits your specific local environment
  before making use of ImageMagick is highly advised. You can find guidance on
  setting up this policy at https://imagemagick.org/security-policy/,
  and it's important to verify your policy using the validation tool located
  at https://imagemagick-secevaluator.doyensec.com/.  We also strongly
  recommend that all users validate their security assumptions by testing their
  configurations after making any policy changes. This helps ensure that the
  intended restrictions are functioning as expected in their specific
  deployment environment.


  Web-safe ImageMagick security policy:

  This security protocol designed for web-safe usage focuses on situations
  where ImageMagick is applied in publicly accessible contexts, like websites.
  It deactivates the capability to read from or write to any image formats
  other than web-safe formats like GIF, JPEG, and PNG. Additionally, this
  policy prohibits the execution of image filters and indirect reads, thereby
  thwarting potential security breaches. By implementing these limitations,
  the web-safe policy fortifies the safeguarding of systems accessible to
  the public, reducing the risk of exploiting ImageMagick's capabilities
  for potential attacks.
-->
<policymap>
  <!-- Set maximum parallel threads. -->
  <policy domain="resource" name="thread" value="2"/>
  <!-- Set maximum time in seconds or mnemonics, e.g. "2 minutes". When this
       limit is exceeded, an exception is thrown and processing stops. -->
  <policy domain="resource" name="time" value="60"/>
  <!-- Set maximum number of open pixel cache files. When this limit is
       exceeded, any subsequent pixels cached to disk are closed and reopened
       on demand. -->
  <policy domain="resource" name="file" value="768"/>
  <!-- Set maximum amount of memory in bytes to allocate for the pixel cache
       from the heap. When this limit is exceeded, the image pixels are cached
       to memory-mapped disk. -->
  <policy domain="resource" name="memory" value="256MiB"/>
  <!-- Set maximum amount of memory map in bytes to allocate for the pixel
       cache. When this limit is exceeded, the image pixels are cached to
       disk. -->
  <policy domain="resource" name="map" value="512MiB"/>
  <!-- Set the maximum width * height of an image that can reside in the pixel
       cache memory. Images that exceed the area limit are cached to disk. -->
  <policy domain="resource" name="area" value="16KP"/>
  <!-- Set maximum amount of disk space in bytes permitted for use by the pixel
       cache. When this limit is exceeded, the pixel cache is not be created
       and an exception is thrown. -->
  <policy domain="resource" name="disk" value="1GiB"/>
  <!-- Set the maximum length of an image sequence.  When this limit is
       exceeded, an exception is thrown. -->
  <policy domain="resource" name="list-length" value="16"/>
  <!-- Set the maximum width of an image.  When this limit is exceeded, an
       exception is thrown. -->
  <policy domain="resource" name="width" value="4KP"/>
  <!-- Set the maximum height of an image.  When this limit is exceeded, an
       exception is thrown. -->
  <policy domain="resource" name="height" value="4KP"/>
  <!-- Periodically yield the CPU for at least the time specified in
       milliseconds. -->
  <policy domain="resource" name="throttle" value="2"/>
  <!-- Dynamically yield the CPU relative to the system load average. -->
  <policy domain="resource" name="dynamic-throttle" value="false"/>
  <!-- Do not create temporary files in the default shared directories, instead
       specify a private area to store only ImageMagick temporary files. -->
  <!-- <policy domain="resource" name="temporary-path" value="/magick/tmp"/> -->
  <!-- Force memory initialization by memory mapping select memory
       allocations. -->
  <policy domain="cache" name="memory-map" value="anonymous"/>
  <!-- Ensure all image data is fully flushed and synchronized to disk. -->
  <policy domain="cache" name="synchronize" value="true"/>
  <!-- Replace passphrase for secure distributed processing -->
  <!-- <policy domain="cache" name="shared-secret" value="secret-passphrase" stealth="true"/> -->
  <!-- Do not permit any external delegates to execute. -->
  <policy domain="delegate" rights="none" pattern="*"/>
  <!-- Do not permit any image filters to load. -->
  <policy domain="filter" rights="none" pattern="*"/>
  <!-- Don't read/write from/to stdin/stdout. -->
  <policy domain="path" rights="none" pattern="-"/>
  <policy domain="path" rights="none" pattern="[Ff][Dd]:*"/>
  <!-- Sensitive paths are not permitted. -->
  <policy domain="path" rights="none" pattern="/etc/*"/>
  <!-- Relative paths are not permitted. -->
  <policy domain="path" rights="none" pattern="*../*"/>
  <!-- Indirect reading is not permitted. -->
  <policy domain="path" rights="none" pattern="@*"/>
  <!-- Deny all image modules and specifically exempt reading or writing
       web-safe image formats. -->
  <policy domain="module" rights="none" pattern="*" />
  <policy domain="module" rights="read | write" pattern="{GIF,JPEG,PNG,WEBP}" />
  <!-- This policy sets the number of times to replace content of certain
       memory buffers and temporary files before they are freed or deleted. -->
  <policy domain="system" name="shred" value="1"/>
  <!-- Enable the initialization of buffers with zeros, resulting in a minor
       performance penalty but with improved security. -->
  <policy domain="system" name="memory-map" value="anonymous"/>
  <!-- Set the maximum amount of memory in bytes that is permitted for
       allocation requests. -->
  <policy domain="system" name="max-memory-request" value="256MiB"/>
  <!-- If the basename of path is a symbolic link, the open fails -->
  <policy domain="system" name="symlink" rights="none" pattern="follow"/>
  <!-- Blocks all SVG entity‑substitution attempts by denying the
    svg:substitute-entities define -->
  <policy domain="system" name="svg" rights="none" pattern="substitute-entities"/>
</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)。

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

自 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 属性,shared-secret 策略不会出现在列表中。

像素缓存同步策略

在将图像像素写入磁盘时,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. 审查 delegates.xml,并通过策略禁用任何不适合你环境的委托。对于保留下来的委托,请使用 configure --with-frozenpaths=yes(原文为 --with--frozenpaths——译者注),确保每个委托程序都使用绝对路径名,例如使用 /usr/bin/gs 而非 gs,从而使委托的解析是确定性的,而不依赖于环境的 PATH。
  7. 阻止执行图像滤镜与间接读取:你可以阻止用户执行图像滤镜和进行间接读取,以提高安全性。
  8. 使用最新版本的 ImageMagick:使用最新版本的 ImageMagick 很重要,可以利用最新的安全修复与更新。