如何在LaTeX文档中去除/剥离特殊字符?

19
我们实现了一项在线服务,可以生成具有预定义结构的PDF。用户可以选择一个LaTeX模板,并使用适当的输入进行编译。
我们担心的问题是安全性,即恶意用户无法通过向LaTeX文档中注入特殊指令来获得shell访问权限。
我们需要一些解决方案,或者至少列出应从输入数据中剥离的特殊字符列表。
首选语言应该是PHP,但欢迎任何建议、构造和链接。
附言:简单地说,我们正在寻找类似于LaTeX的mysql_real_escape_string函数的函数。

我不确定LaTeX中可以编写什么样的恶意代码,但我非常确定在LaTeX中没有与mysql_real_escape_string相当的PHP等效函数。我想你只需要想出一些正则表达式来剪切掉你不想要的行,只要你知道你要找什么。 - Ben Torell
我已经回答了这个问题,但后来意识到我不确定我的答案是否解决了这个问题。我们在谈论什么样的模板:基于典型网络表单的模板,还是一些带有latex标记的上传文件?后者是我独立思考的一个问题... - Charles Stewart
@Charles Stewart:这个问题是在从Web表单输入生成PDF时出现的,但关于上传的更一般的问题也很有趣! - Igor
5个回答

18

这里有一些代码来实现Geoff Reedy的答案。我将这段代码放在公共领域中。

<?

$test = "Test characters: # $ % & ~ _ ^ \ { }.";
header( "content-type:text/plain" );
print latexSpecialChars( $test );
exit;

function latexSpecialChars( $string )
{
    $map = array( 
            "#"=>"\\#",
            "$"=>"\\$",
            "%"=>"\\%",
            "&"=>"\\&",
            "~"=>"\\~{}",
            "_"=>"\\_",
            "^"=>"\\^{}",
            "\\"=>"\\textbackslash",
            "{"=>"\\{",
            "}"=>"\\}",
    );
    return preg_replace( "/([\^\%~\\\\#\$%&_\{\}])/e", "\$map['$1']", $string );
}

6
为确保反斜杠紧接在文本之前时能够正确处理,您需要将“\textbackslash”更改为“\textbackslash{}”。我尝试进行编辑,但stackoverflow不允许编辑两个字符 :-( - david

3
据我所知,使用LaTeX进行有害操作的唯一可能性是启用使用\write18调用外部命令的功能。这仅在您使用--shell-escape或--enable-write18参数(取决于您的发行版)运行LaTeX时才有效。
只要您不使用其中之一的参数运行它,您就应该可以安全地使用而无需过滤任何部分。
此外,人们仍然可以使用\newwrite\openout\write命令编写其他文件。让用户创建和(覆盖)写入文件可能是不希望的?因此,您可以过滤掉这些命令的出现。但是,保留某些命令的黑名单容易失败,因为有恶意意图的人可以通过混淆输入文档来轻松隐藏实际命令。
编辑:在禁用\write18的情况下,使用受限帐户(即不写入非latex/项目相关目录)运行LaTeX命令可能比保留“危险”命令的黑名单更容易和更安全。

谢谢Veger!你的回答和Geoff的Reedy帖子结合起来,给出了完美的防入侵收据。 - Igor
1
用户可能编写恶意的占用CPU资源的LaTeX循环。 - Dave Jarvis
用户仍然可以通过使用\input{/etc/passwd}读取任意文件。 - pcworld

3
根据http://www.tug.org/tutorials/latex2e/Special_Characters.html, LaTeX 中的特殊字符包括# $ % & ~ _ ^ \ { }。大多数可以用一个反斜杠进行转义,但是_^\需要特殊处理。
要使用脱字符,请使用\^{}(或\textasciicircum),要使用波浪号请使用\~{}(或\textasciitilde),要使用反斜杠请使用\textbackslash
如果您希望用户输入以打字机文本形式显示,还可以使用\verb命令,例如\verb+asdf$$&\~^+,其中的+可以是任何字符,但不能在文本中出现。

是的,但这些字符对OP的在线服务不构成安全威胁。 - Veger
1
如果你转义这些字符,特别是 \,那么你就可以防止它们插入任何标记。这是最接近 mysql_real_escape_string 的等效方法。 - staticsan
@Veger:是的,因为符号“ ' ”在SQL查询中不会造成伤害,但必须放在正确的位置。如果您不想允许注入某些LaTeX特定的特殊字符,您需要以与SQL查询相同的方式转义它们。我一直在寻找这个答案,并找到了非常恰当的答案! - Igor

3
一般来说,仅通过转义命令序列实现安全性很难做到,因为没有原则性的方法可以区分安全的cs和不安全的cs:TeX并不是足够清洁的编程语言来允许这样做。我建议放弃这种方法,而是采用消除安全漏洞的方法。
Veger对Latex中的安全漏洞的总结与我的相符,即问题在于shell escape和文件创建/覆盖,尽管他忽略了一个shell escape漏洞。接下来是一些附加点,然后是一些建议:
  1. 仅仅避免主动调用 --shell-escape 是不够的,因为它可能会在 texmf.cnf 中被隐式启用。你应该显式地传递 --no-shell-escape 来覆盖 texmf.cnf;
  2. \write18 是 Etex 的原语,而不是 Knuth's Tex。因此,你可以避免实现它的 Latexes(不幸的是,大部分都实现了);
  3. 如果你使用 Dvips,则存在另一个风险: \special 命令可以创建 .dvi 文件来要求 dvips 执行 shell 命令。因此,如果您使用 dvips,则应该传递 -R2 命令来禁止调用 shell 命令;
  4. texmf.cnf 允许你指定 Tex 可以创建文件的位置;
  5. 如果您希望客户有更多选择字体的自由度,则可能无法避免禁用字体的创建。请参阅Kpathsea安全注释;默认行为对我来说似乎是合理的,但您可以拥有每个用户的字体树,以防止一个用户惹恼另一个用户。

选项:

  1. 将客户端的Latex调用隔离,并允许他们在沙盒中自由行事;
  2. 信任kpathsea的默认设置,在latex和任何其他用于构建PDF输出的可执行文件中禁止shell转义;
  3. 大幅降低表达能力,禁止客户创建字体文件或任何新的客户指定文件。作为一个只能写入某些已经存在的文件的进程运行latex;
  4. 您可以创建一个格式文件,在其中未绑定\write18 cs和文件创建css,只存在调用它们安全的宏,例如用于字体/toc/bbl创建的宏。这意味着您必须决定客户端拥有哪些功能:他们将无法自由选择导入哪些包,而必须使用您强加给他们的选择。根据您所考虑的“模板”类型,这可能是一个不错的选择,允许使用使用shell转义的包,但您需要审核进入格式文件的Tex/Latex代码。

后记

有一篇TUGBoat文章(基于LATEX模板的服务器端PDF生成),探讨了另一种从表单输入生成PDF的方法,与我采用的方法不同。


谢谢Charles!您的解释超出了我的LaTeX经验。最后一个链接对我非常有用,那篇文章末尾的参考资料提供了很多关于这个主题的阅读来源。 - Igor


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接