如何在LaTeX文档中转义/删除特殊字符?

时间:2010-03-29 22:10:14

标签: php latex escaping strip

我们实施了在线服务,可以使用预定义生成PDF 结构体。用户可以选择LaTeX模板,然后使用适当的输入进行编译。

我们担心的问题是安全性,恶意用户无法通过在乳胶文档中注入特殊指令来获取shell访问权。

我们需要一些解决方法或至少我们应该从输入数据中删除的特殊字符列表。

首选语言是PHP,但非常欢迎任何建议,结构和链接。

PS。简而言之,我们正在为LaTeX寻找 mysql_real_escape_string

6 个答案:

答案 0 :(得分:15)

这是一些实现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 );
}

答案 1 :(得分:3)

使用LaTeX执行有害操作的唯一可能性(AFAIK)是允许使用\write18调用外部命令。这只适用于使用--shell-escape或--enable-write18参数运行LaTeX(取决于您的发行版)。

因此,只要您不使用其中一个参数运行它,您就应该是安全的,而无需过滤掉任何部分。

除此之外,还可以使用\newwrite\openout\write命令编写其他文件。让用户创建和(重写)写入文件可能不受欢迎?因此,您可以过滤掉这些命令的出现次数。但是保留某些命令的黑名单很容易失败,因为有意图的人可以通过捏造输入文档来轻易隐藏实际命令。

编辑:使用受限帐户运行LaTeX命令(即不写入非乳胶/项目相关目录)以及禁用\write18可能比保持一个更简单,更安全“危险”命令黑名单。

答案 2 :(得分:3)

一般而言,如果没有大幅度降低表达性,很难实现纯粹通过转义命令序列来实现安全性,因为没有原则上的方法来区分安全的cs和不安全的cs:Tex只是不够干净的编程语言来实现这一点。我会说放弃这种做法有利于消除安全漏洞的存在。

Veger对Latex中安全漏洞的总结符合我的要求:即问题是shell转义和文件创建。覆盖,尽管他已经错过了shell逃逸漏洞。接下来是一些其他要点,然后是一些建议:

  1. 仅限于主动调用--shell-escape是不够的,因为它可以在texmf.cnf中隐式启用。您应该明确传递--no-shell-escape以覆盖texmf.cnf;
  2. \write18是Etex的原语,而不是Knuth的Tex。所以你可以避免实现它的Latexes(不幸的是,它们中的大多数都是这样);
  3. 如果您使用Dvips,还有另一个风险:\special命令可以创建.dvi文件,要求dvips执行shell命令。因此,如果使用dvips,则应该传递-R2命令以禁止调用shell命令;
  4. texmf.cnf允许您指定Tex可以创建文件的位置;
  5. 如果您希望客户可以自由创建字体,则可能无法避免禁用字体创建。看看the notes on security for Kpathsea;默认行为对我来说似乎是合理的,但你可以有一个每用户字体树,以防止一个用户踩到另一个用户脚趾。
  6. 选项:

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

      有一篇TUGBoat文章,Server side PDF generation based on LATEX templates,针对我所采取的问题解决了另一个问题,即使用Latex从表单输入生成PDF。

答案 3 :(得分:2)

根据http://www.tug.org/tutorials/latex2e/Special_Characters.html,乳胶中的特殊字符为# $ % & ~ _ ^ \ { }。大多数都可以使用简单的反斜杠进行转义,但_ ^\需要特殊处理。

对于使用\^{}(或\textasciicircum)的插入符号,使用\~{}(或\textasciitilde)和反斜杠使用\textbackslash

如果您希望用户输入显示为打字机文本,还有\verb命令可以像\verb+asdf$$&\~^+一样使用,+可以是任何字符,但不能在文中。

答案 4 :(得分:0)

答案 5 :(得分:0)

在Scala中,我正在使用此代码段。

package punychar.rellyfiler.latex

object LaTexEscape {

   def textbf_boldfont(x: String): String = s"\\textbf{${x}}"

   def escapeSpecialCharacters(input: String): String = {
      return if (input == null) null
      else
         input
            .replaceAll("\\\\", "\\\\textbackslash ")
            .replaceAll("([#$%&_{}])", "\\\\$1")
            .replaceAll("([<>])", "\\\u0024$1\\\u0024")
            .replaceAll("~", "\\\\textasciitilde ")
            .replaceAll("\\^", "\\\\textasciicircum ")
   }

}

以及这些测试

package punychar.rellyfiler.latex

import org.scalatest.FlatSpec

import punychar.rellyfiler.latex.LaTexEscape.escapeSpecialCharacters

class Test extends FlatSpec {

   "LaTex Escape" should "escape basic special characters by preceding backslash" in {
      assert(escapeSpecialCharacters("&%$#_{}") == "\\&\\%\\$\\#\\_\\{\\}")
   }

   "LaTex Escape" should "should describe tilde by words" in {
      assert(escapeSpecialCharacters("~") == "\\textasciitilde ")
   }

   "LaTex Escape" should "should describe circum by words" in {
      assert(escapeSpecialCharacters("^") == "\\textasciicircum ")
   }

   "LaTex Escape" should "should desribe backslash by words" in {
      assert(escapeSpecialCharacters("\\") == "\\textbackslash ")
   }

   "LaTex Escape" should "deal with combinations of special characters, too" in {
      assert(escapeSpecialCharacters("~blabla\\x") == "\\textasciitilde blabla\\textbackslash x")
   }
}