Как безопасно обрабатывать пользовательский ввод в Юникоде в Scala (особенно в XML-сущностях) - PullRequest
4 голосов
/ 09 января 2010

На моем веб-сайте есть форма, в которой вводятся текстовые данные пользователя. Все отлично работает для "нормальных" персонажей. Однако, когда вводятся символы Юникода ... ну, сюжет утолщается.

Пользователь вводит что-то вроде

やっぱ死にかけてる

Это приходит на сервер в виде текста, содержащего ссылку на сущность XML

やっぱ死にかけてる?

Теперь, когда я хочу передать это обратно клиенту в HTML, как мне это сделать?

Если я просто выведу строку в том виде, в каком она есть, возможна атака сценария. Если я пытаюсь закодировать его с помощью scala.xml.Text, оно преобразуется в:

やっぱ死にかけてる?

Есть ли в Scala лучшее готовое решение, которое может обнаруживать ссылки на сущности и не избегать их, но избегать тегов XML?

Ответы [ 4 ]

5 голосов
/ 11 января 2010

Анализ строки, содержащей ссылки на сущности, как фрагмента XML. Чтобы безопасно выводить символы Юникода в XML, вы можете быть параноиком и использовать для них ссылки на сущности XML согласно функции escape

scala>import xml.parsing.ConstructingParser                                                             
import xml.parsing.ConstructingParser

scala>import io.Source                                                                                  
import io.Source

scala> val d = ConstructingParser.fromSource(Source.fromString("<dummy>&#12420;</dummy>"), true).documnent
d: scala.xml.Document = <dummy>や</dummy>

scala>val t = d(0).text                                                                                         
res0: String = や

scala> import xml._
import xml._

scala> def escape(xmlText: String): NodeSeq = {
     |   def escapeChar(c: Char): xml.Node =
     |     if (c > 0x7F || Character.isISOControl(c))
     |       xml.EntityRef("#" + Integer.toString(c, 10))
     |     else
     |       xml.Text(c.toString)
     | 
     |   new xml.Group(xmlText.map(escapeChar(_)))
     | }
escape: (xmlText: String)scala.xml.NodeSeq

scala> <foo>{escape(t)}</foo>                            
res3: scala.xml.Elem = <foo>&#12420;</foo>
1 голос
/ 09 января 2010

Хорошо, я пробую этот простой взлом. Комментарии приветствуются:

def secureEscape(text: String) = {
  val s = new StringBuilder()
  for (c <- text.elements) c match {
   case '<' => s.append("&lt;")
   case '>' => s.append("&gt;")
   case _   => s.append(c)
  }
  s.toString
}

Это в основном ускользнет < и >.

Затем я использую эту функцию, чтобы проанализировать входящие данные формы и затем передать их без дальнейшей обработки клиенту.

0 голосов
/ 13 января 2010

Браузеры кодируют входные символы в числовые ссылочные объекты, только если этот символ находится за пределами набора символов, в котором была обслужена страница. Избавьте себя от множества проблем и обслуживайте свои страницы в UTF-8, правильно помеченные как UTF-8. Обработка строк в Scala, Java и Javascript выполняется в Юникоде, и ограничение iso-8859-1 для ваших веб-страниц вызывает подобные проблемы во всех направлениях. Если ваш существующий контент - ASCII, то преобразование должно быть безболезненным.

0 голосов
/ 09 января 2010

Действительно, браузер должен отвечать за правильную кодировку UTF-8 и экранирование символов (это, похоже, происходит). Ваш веб-фреймворк должен затем обрабатывать удаление и декодирование.

Это может быть сложный бизнес, включающий несколько этапов, каждый из которых может быть явно настроен для корректной работы UTF-8. Особенно при работе со старыми платформами и серверами, кеширующими прокси, сетями доставки контента и т. Д.

Дело в том, что внутри вы хотите видеть ожидаемые символы Юникода, а не ссылки на сущности. Точно так же вы должны выводить собственный юникод и обрабатывать требуемую кодировку на границе вашей системы, предпочтительно это будет автоматически обрабатываться вашим выбором веб-фреймворка.

Чтобы дать вам правильное решение, необходимо знать, какой программный стек (ы) вы используете и как отправляется форма (т.е. GET / POST / AJAX + JSON)

...