Rails 5 — Как удалить теги из строки в rails (НЕ в / для html)

#ruby-on-rails #strip-tags

#ruby-on-rails #strip-теги

Вопрос:

Мне нужно удалить теги из пользовательского ввода перед сохранением в БД

Я хорошо знаком с методом strip_tags, но он также экранирует строку html, как и все другие рекомендуемые методы:

 Rails::Html::FullSanitizer.new.sanitize 'amp;'
 => "amp;amp;" 
Rails::Html::WhiteListSanitizer.new.sanitize('amp;', tags: [])
 => "amp;amp;" 
ActionController::Base.helpers.strip_tags "amp;"
 => "amp;amp;" 

 

Строка, которую я хочу очистить, НЕ должна экранироваться, она экспортируется через API, используется в файлах и т. Д. он выводится не только через HTML (где также в таких случаях, как link_to ActionController::Base.helpers.strip_tags("amp;") — link_to — двойная экранирующая строка, поэтому вы получите ссылку amp;amp; на интерфейс)

В качестве исправления для обезьян я включил strip_tags, CGI.unescapeHTML чтобы получить более или менее ожидаемый результат, но хочу найти какое-то прямое решение (я также боюсь, что еще может сделать strip_tags, и для этой небольшой функциональности слишком много движущихся частей — больше вещей, которые могут пойти не так или сломаться)

Пример реального мира: JPMorgan Chase amp; Co должен стать JPMorgan Chase amp; Co после удаления тегов

test<script>alert('hacked!');</script>amp;test должно стать testamp;test после удаления тегов

А также строка:

 "test amp;#x3C;scriptamp;#x3E;alert(amp;#x27;hacked!amp;#x27;)amp;#x3C;/scriptamp;#x3E;"
 

Все равно должно быть

 "test amp;#x3C;scriptamp;#x3E;alert(amp;#x27;hacked!amp;#x27;)amp;#x3C;/scriptamp;#x3E;"
 

После удаления HTML’ов

С альтернативными решениями, которые я нашел или которые были предложены:

 > Nokogiri::HTML("test amp;#x3C;scriptamp;#x3E;alert(amp;#x27;hacked!amp;#x27;)amp;#x3C;/scriptamp;#x3E;").text
 => "test <script>alert('hacked!')</script>"

> Loofah.fragment("test amp;#x3C;scriptamp;#x3E;alert(amp;#x27;hacked!amp;#x27;)amp;#x3C;/scriptamp;#x3E;").text(encode_special_chars: false)
 => "test <script>alert('hacked!')</script>"

 

Так что они тоже не подходят

Комментарии:

1. Можете ли вы привести пример рассматриваемой строки и желаемого результата?

2. Я обновил информацию на примере реального мира

Ответ №1:

Вы должны проанализировать HTML и извлечь текстовые элементы. Для этого используйте Nokogiri.

 Nokogiri::HTML("<div>Strip <i>this</i> amp; <b>this</b> amp; <u>this</u>!</div>").text
 

Nokogiri уже используется Rails, поэтому его использование не требует затрат.


Вы получите весь текст, включая содержимое <script> тегов.

 Nokogiri::HTML(%q[test<script>alert('hacked!');</script>amp;test]).text

# testalert('hacked!');amp;test
 

Вы можете удалить <script> теги.

 doc = Nokogiri::HTML(%q[test<script>alert('hacked!');</script>amp;test])
doc.search('//script').each { |node| node.replace('') }
doc.text

# testamp;test
 

Но с удаленными тегами строка не причинит вреда. Возможно, это не стоит затраченных усилий.

Подробнее см. В уроках Nokogiri.

Комментарии:

1. О, это именно то, что я искал! Спасибо!

2. Ах, нет, извините, это не сработает: (См. Мое обновление внизу вопроса

3. @HandsomeJack Каков ваш конечный результат? Защищаете ли вы от внедрения HTML? Или вы извлекаете текст из HTML? Похоже, что и то, и другое. Это разные вещи. Если оба, извлеките текст, а затем экранируйте любой HTML, который мог скрываться в тексте. Но вы уже должны экранировать свой текст перед его использованием, а не при его сохранении; таким образом, вы не догадываетесь, как он будет использоваться. Извлеките текст, сохраните его в базе данных. Затем вы можете использовать его для чего угодно. Затем экранируйте любой текст, прежде чем поместить его в HTML, не думайте, что он уже экранирован.