Как безопасно обрабатывать пользовательский ввод в Unicode в Scala (особенно в XML-сущностях)

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

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

やっぱ死にかけてる

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

やっぱ死にかけてる?

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

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

やっぱ死にかけてる?

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

4 ответа

Решение

Разобрать строку, содержащую ссылки на сущности, как фрагмент XML. Чтобы безопасно выводить символы Unicode в 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>

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

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
}

Это в основном сбежать < а также >,

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

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

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

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

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

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

Другие вопросы по тегам