discourse/lib/onebox/sanitize_config.rb
Natalie Tay 188cb58daa
SECURITY: Fixes for main (#28137)
* SECURITY: Update default allowed iframes list

Change the default iframe url list to all include 3 slashes.

* SECURITY: limit group tag's name length

Limit the size of a group tag's name to 100 characters.

Internal ref - t/130059

* SECURITY: Improve sanitization of SVGs in Onebox

---------

Co-authored-by: Blake Erickson <o.blakeerickson@gmail.com>
Co-authored-by: Régis Hanol <regis@hanol.fr>
Co-authored-by: David Taylor <david@taylorhq.com>
2024-07-30 14:19:01 +08:00

119 lines
3.8 KiB
Ruby

# frozen_string_literal: true
module Onebox
module SanitizeConfig
HTTP_PROTOCOLS ||= ["http", "https", :relative].freeze
ONEBOX ||=
Sanitize::Config.freeze_config(
Sanitize::Config.merge(
Sanitize::Config::RELAXED,
elements:
Sanitize::Config::RELAXED[:elements] +
%w[audio details embed iframe source video svg path use],
attributes: {
"a" => Sanitize::Config::RELAXED[:attributes]["a"] + %w[target],
"audio" => %w[controls controlslist],
"embed" => %w[height src type width],
"iframe" => %w[
allowfullscreen
frameborder
height
scrolling
src
width
data-original-href
data-unsanitized-src
],
"source" => %w[src type],
"video" => %w[
controls
height
loop
width
autoplay
muted
poster
controlslist
playsinline
],
"path" => %w[d fill-rule],
"svg" => %w[aria-hidden width height viewbox],
"div" => [:data], # any data-* attributes,
"span" => [:data], # any data-* attributes,
"use" => %w[href],
},
add_attributes: {
"iframe" => {
"seamless" => "seamless",
"sandbox" =>
"allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox" \
" allow-presentation",
},
},
transformers:
(Sanitize::Config::RELAXED[:transformers] || []) +
[
lambda do |env|
next unless env[:node_name] == "a"
a_tag = env[:node]
a_tag["href"] ||= "#"
if a_tag["href"] =~ %r{\A(?:[a-z]+:)?//}
a_tag["rel"] = "nofollow ugc noopener"
else
a_tag.remove_attribute("target")
end
end,
lambda do |env|
next unless env[:node_name] == "iframe"
iframe = env[:node]
allowed_regexes = env[:config][:allowed_iframe_regexes] || [/.*/]
allowed = allowed_regexes.any? { |r| iframe["src"] =~ r }
if !allowed
# add a data attribute with the blocked src. This is not required
# but makes it much easier to troubleshoot onebox issues
iframe["data-unsanitized-src"] = iframe["src"]
iframe.remove_attribute("src")
end
end,
lambda do |env|
next if env[:node_name] != "svg"
env[:node].traverse do |node|
next if node.element? && %w[svg path use].include?(node.name)
node.remove
end
end,
],
protocols: {
"embed" => {
"src" => HTTP_PROTOCOLS,
},
"iframe" => {
"src" => HTTP_PROTOCOLS,
},
"source" => {
"src" => HTTP_PROTOCOLS,
},
"use" => {
"href" => [:relative],
},
},
css: {
properties: Sanitize::Config::RELAXED[:css][:properties] + %w[--aspect-ratio],
},
),
)
DISCOURSE_ONEBOX ||=
Sanitize::Config.freeze_config(
Sanitize::Config.merge(
ONEBOX,
attributes: Sanitize::Config.merge(ONEBOX[:attributes], "aside" => [:data]),
),
)
end
end