Module: OrdarsRailsEditor::Sanitizer
- Defined in:
- lib/ordars_rails_editor/sanitizer.rb
Overview
에디터 저장 HTML 서버측 새니타이저 — 저장형 XSS 방어의 정본.
⭐호스트 앱은 «저장 직전» 반드시 이걸 통과시킨다: post.content = OrdarsRailsEditor::Sanitizer.clean(params) 클라이언트(에디터)가 만드는 HTML 스키마와 이 화이트리스트는 한 쌍 — 에디터에 서식을 추가하면 여기 허용 목록도 함께 넓힌다(안 넓히면 저장 시 조용히 벗겨진다 — 의도된 동작).
style 속성은 통째 허용하지 않고 «속성 단위»로 거른다(color/background-color/font-size/text-align).
Constant Summary collapse
- ALLOWED_TAGS =
⚠에디터 서식과 «한 쌍» — mark=형광펜(Highlight), data-color=Highlight 색 속성(0.1.1 에서 누락 실사고:
형광펜 적용 글이 저장 시 조용히 벗겨짐). %w[p br strong b em i s del u code pre blockquote ul ol li h1 h2 h3 hr a img span mark].freeze
- ALLOWED_ATTRIBUTES =
%w[href target rel src alt width height style data-file-id data-color].freeze
- ALLOWED_STYLE_PROPS =
%w[color background-color font-size text-align].freeze
- ALLOWED_URI_SCHEMES =
%w[http https mailto tel].freeze
Class Method Summary collapse
Class Method Details
.base_sanitizer ⇒ Object
65 66 67 |
# File 'lib/ordars_rails_editor/sanitizer.rb', line 65 def base_sanitizer @base_sanitizer ||= Rails::HTML5::SafeListSanitizer.new end |
.clean(html) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/ordars_rails_editor/sanitizer.rb', line 22 def clean(html) return "" if html.nil? || html.to_s.strip.empty? sanitized = base_sanitizer.sanitize( html.to_s, tags: ALLOWED_TAGS, attributes: ALLOWED_ATTRIBUTES, scrubber: nil ) frag = Loofah.fragment(sanitized) # style 은 허용 속성만 통과 frag.css("[style]").each do |node| filtered = filter_style(node["style"]) filtered.empty? ? node.remove_attribute("style") : (node["style"] = filtered) end # 링크: 스킴 화이트리스트 + 새 탭 안전 rel frag.css("a").each do |a| href = a["href"].to_s.strip scheme = href[/\A([a-z][a-z0-9+.-]*):/i, 1]&.downcase if href.empty? || (scheme && !ALLOWED_URI_SCHEMES.include?(scheme)) a.remove_attribute("href") end a["rel"] = "noopener noreferrer" if a["target"].to_s == "_blank" end frag.to_s end |
.filter_style(style) ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/ordars_rails_editor/sanitizer.rb', line 53 def filter_style(style) style.to_s.split(";").filter_map do |decl| prop, value = decl.split(":", 2) next if prop.nil? || value.nil? prop = prop.strip.downcase value = value.strip next unless ALLOWED_STYLE_PROPS.include?(prop) next if value.match?(/url\s*\(|expression|javascript/i) "#{prop}: #{value}" end.join("; ") end |