Как вывести/убрать специальные символы в документе LaTeX?

Мы внедрили онлайн-сервис, где можно создавать PDF с предопределенным состав. Пользователь может выбрать шаблон LaTeX, а затем скомпилировать его с соответствующими входами.

Вопрос, о котором мы беспокоимся, - это безопасность, что злоумышленник не смог получить доступ к оболочке через инъекцию специальной инструкции в латексный документ.

Нам нужно обходное решение для этого или, по крайней мере, списка специальных символов, которые мы должны удалить из входных данных.

Предпочтительным языком будет PHP, но любые предложения, конструкции и ссылки приветствуются.

PS. в нескольких словах мы ищем mysql_real_escape_string для LaTeX

Ответы

Ответ 1

Единственная возможность (AFAIK) выполнять вредные операции с использованием LaTeX - это возможность возможности вызова внешних команд с помощью \write18. Это работает только при запуске LaTeX с аргументом -shell-escape или -enable-write18 (в зависимости от вашего дистрибутива).

Итак, пока вы не запускаете его с одним из этих аргументов, вы должны быть в безопасности, не отфильтровывая какие-либо части.

Кроме того, все еще можно записывать другие файлы с помощью команд \newwrite, \openout и \write. Может ли пользователь создавать и (над) писать файлы, может быть нежелательным? Таким образом, вы можете отфильтровать вхождения этих команд. Но сохранение черных списков определенных команд подвержено ошибкам, так как кто-то с плохим намерением может легко скрыть действительную команду, опуская входной документ.

Изменить: запуск команды LaTeX с использованием ограниченной учетной записи (т.е. отсутствие записи в каталоги, не связанные с латекс/проект) в сочетании с отключением \write18, может быть проще и безопаснее, чем содержать черный список "опасных" команд.

Ответ 2

Вот какой код для реализации ответа Джеффа Риди. Я размещаю этот код в общедоступном домене.

<?

$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 );
}

Ответ 3

В целом, достижение безопасности исключительно посредством экранирования командных последовательностей трудно обойтись без радикального уменьшения выразительности, поскольку нет принципиального способа отличить безопасные cs от небезопасных: Tex - это просто не достаточно чистый язык программирования, чтобы это разрешить. Я бы сказал, отказаться от этого подхода в пользу устранения наличия дыр в безопасности.

Резюме ошибок безопасности в Latex соответствует моей работе: например, проблемы - это экранирование оболочки и создание файла. Перезапись, хотя он и упустил уязвимость при выходе из оболочки. Далее следуют некоторые дополнительные пункты, затем некоторые рекомендации:

  • Недостаточно избегать активного вызова --shell-escape, поскольку он может быть неявно включен в texmf.cnf. Вы должны явно передать --no-shell-escape для переопределения texmf.cnf;
  • \write18 - это примитив Etex, а не Knuth Tex, поэтому вы можете избежать латексов, которые его реализуют (что, к сожалению, большинство из них);
  • Если вы используете Dvips, существует еще один риск: команды \special могут создавать файлы .dvi, которые запрашивают dvips для выполнения команд оболочки. Поэтому, если вы используете dvips, передайте команду -R2, чтобы запретить вызов команд оболочки;
  • texmf.cnf позволяет указать, где Tex может создавать файлы;
  • Возможно, вам не удастся отключить создание шрифтов, если вы хотите, чтобы ваши клиенты имели большую свободу в том, какие шрифты они могут создавать. Взгляните на заметки о безопасности для Kpathsea; поведение по умолчанию кажется мне разумным, но вы можете иметь дерево пользовательских шрифтов, чтобы один пользователь не ступил на другие пальцы пользователей.

Параметры:

  • Песочница для ваших клиентских латексных вызовов и позволяйте им свободно ошибаться в песочнице;
  • Доверяйте значениям по умолчанию kpathsea и запрещайте экранировать оболочки в латекс и любые другие исполняемые файлы, используемые для создания PDF файла;
  • Резко уменьшить выразительность, запрещая вашим клиентам возможность создавать файлы шрифтов или любые новые файлы, указанные клиентом. Запускайте латекс как процесс, который может записывать только некоторые уже существующие файлы;
  • Вы можете создать файл формата, в котором \write18 cs и создание файла css не связаны, и существуют только макросы, которые вызывают их безопасно, например, для создания шрифта /toc/bbl. Это означает, что вам нужно решить, какие функции у ваших клиентов есть: они не смогут свободно выбирать, какие пакеты им импортировать, но должны использовать выбранные вами варианты. В зависимости от того, какие "шаблоны" вы имеете в виду, это может быть хорошим вариантом, позволяющим использовать пакеты, которые используют экраны оболочки, но вам нужно будет проверить код Tex/Latex, который входит в ваш файл формата.

Postscript

Там есть статья TUGBoat, Генерация на стороне сервера на основе шаблонов LATEX, обращаясь к другому вопросу, к вопросу, которое я взял, а именно создание PDF файлов из ввода формы с использованием латекса.

Ответ 4

В соответствии с http://www.tug.org/tutorials/latex2e/Special_Characters.html специальные символы в латексе # $ % & ~ _ ^ \ { }. Большинство из них можно избежать с помощью простой обратной косой черты, но _ ^ и \ нуждаются в специальной обработке.

Для использования каретки \^{} (или \textasciicircum) для использования тильды \~{} (или \textasciitilde) и для обратного слэша используйте \textbackslash

Если вы хотите, чтобы пользовательский ввод отображался в виде текста пишущей машинки, есть также команда \verb, которая может использоваться как \verb+asdf$$&\~^+, + может быть любым символом, но не может быть в тексте.

Ответ 6

В 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")
   }
}