mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
DEV: add validation on content_security_policy_script_src site setting (#27564)
* DEV: add validation on content_security_policy_script_src site setting
This commit is contained in:
parent
ca4af53be8
commit
60d5170587
|
@ -1844,7 +1844,7 @@ en:
|
||||||
content_security_policy_report_only: "Enable Content-Security-Policy-Report-Only (CSP)"
|
content_security_policy_report_only: "Enable Content-Security-Policy-Report-Only (CSP)"
|
||||||
content_security_policy_collect_reports: "Enable CSP violation report collection at /csp_reports"
|
content_security_policy_collect_reports: "Enable CSP violation report collection at /csp_reports"
|
||||||
content_security_policy_frame_ancestors: "Restrict who can embed this site in iframes via CSP. Control allowed hosts on <a href='%{base_path}/admin/customize/embedding'>Embedding</a>"
|
content_security_policy_frame_ancestors: "Restrict who can embed this site in iframes via CSP. Control allowed hosts on <a href='%{base_path}/admin/customize/embedding'>Embedding</a>"
|
||||||
content_security_policy_script_src: "Additional allowlisted script sources. The current host and CDN are included by default. See <a href='https://meta.discourse.org/t/mitigate-xss-attacks-with-content-security-policy/104243' target='_blank'>Mitigate XSS Attacks with Content Security Policy.</a> (CSP). Host sources will be ignored when content_security_policy_strict_dynamic is enabled."
|
content_security_policy_script_src: "Additional allowlisted script sources. The current host and CDN are included by default. See <a href='https://meta.discourse.org/t/mitigate-xss-attacks-with-content-security-policy/104243' target='_blank'>Mitigate XSS Attacks with Content Security Policy.</a> (CSP). Other host sources are ignored as strict-dynamic is enabled."
|
||||||
invalidate_inactive_admin_email_after_days: "Admin accounts that have not visited the site in this number of days will need to re-validate their email address before logging in. Set to 0 to disable."
|
invalidate_inactive_admin_email_after_days: "Admin accounts that have not visited the site in this number of days will need to re-validate their email address before logging in. Set to 0 to disable."
|
||||||
include_secure_categories_in_tag_counts: "When enabled, count of topics for a tag will include topics that are in read restricted categories for all users. When disabled, normal users are only shown a count of topics for a tag where all the topics are in public categories."
|
include_secure_categories_in_tag_counts: "When enabled, count of topics for a tag will include topics that are in read restricted categories for all users. When disabled, normal users are only shown a count of topics for a tag where all the topics are in public categories."
|
||||||
display_personal_messages_tag_counts: "When enabled, count of personal messages tagged with a given tag will be displayed."
|
display_personal_messages_tag_counts: "When enabled, count of personal messages tagged with a given tag will be displayed."
|
||||||
|
@ -2689,6 +2689,7 @@ en:
|
||||||
invalid_reply_by_email_address: "Value must contain '%{reply_key}' and be different from the notification email."
|
invalid_reply_by_email_address: "Value must contain '%{reply_key}' and be different from the notification email."
|
||||||
invalid_alternative_reply_by_email_addresses: "All values must contain '%{reply_key}' and be different from the notification email."
|
invalid_alternative_reply_by_email_addresses: "All values must contain '%{reply_key}' and be different from the notification email."
|
||||||
invalid_domain_hostname: "Must not include * or ? characters."
|
invalid_domain_hostname: "Must not include * or ? characters."
|
||||||
|
invalid_csp_script_src: "Value must be either 'unsafe-eval' or 'wasm-unsafe-eval', or in the form '<hash algorithm>-<base64 value>' where supported hash algorithms are sha256, sha384 or sha512. Ensure that your input is wrapped in single quotation marks."
|
||||||
pop3_polling_host_is_empty: "You must set a 'pop3 polling host' before enabling POP3 polling."
|
pop3_polling_host_is_empty: "You must set a 'pop3 polling host' before enabling POP3 polling."
|
||||||
pop3_polling_username_is_empty: "You must set a 'pop3 polling username' before enabling POP3 polling."
|
pop3_polling_username_is_empty: "You must set a 'pop3 polling username' before enabling POP3 polling."
|
||||||
pop3_polling_password_is_empty: "You must set a 'pop3 polling password' before enabling POP3 polling."
|
pop3_polling_password_is_empty: "You must set a 'pop3 polling password' before enabling POP3 polling."
|
||||||
|
|
|
@ -2025,6 +2025,7 @@ security:
|
||||||
content_security_policy_script_src:
|
content_security_policy_script_src:
|
||||||
type: simple_list
|
type: simple_list
|
||||||
default: ""
|
default: ""
|
||||||
|
validator: "CspScriptSrcValidator"
|
||||||
invalidate_inactive_admin_email_after_days:
|
invalidate_inactive_admin_email_after_days:
|
||||||
default: 365
|
default: 365
|
||||||
min: 0
|
min: 0
|
||||||
|
|
22
lib/validators/csp_script_src_validator.rb
Normal file
22
lib/validators/csp_script_src_validator.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class CspScriptSrcValidator
|
||||||
|
VALID_SOURCE_REGEX =
|
||||||
|
/
|
||||||
|
(?:\A'unsafe-eval'\z)|
|
||||||
|
(?:\A'wasm-unsafe-eval'\z)|
|
||||||
|
(?:\A'sha(?:256|384|512)-[A-Za-z0-9+\/\-_]+={0,2}'\z)
|
||||||
|
/x
|
||||||
|
|
||||||
|
def initialize(opts = {})
|
||||||
|
@opts = opts
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_value?(values)
|
||||||
|
values.split("|").all? { _1.match? VALID_SOURCE_REGEX }
|
||||||
|
end
|
||||||
|
|
||||||
|
def error_message
|
||||||
|
I18n.t("site_settings.errors.invalid_csp_script_src")
|
||||||
|
end
|
||||||
|
end
|
|
@ -129,16 +129,6 @@ RSpec.describe ContentSecurityPolicy do
|
||||||
expect(parse(policy)["script-src"]).to include("'unsafe-eval'")
|
expect(parse(policy)["script-src"]).to include("'unsafe-eval'")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "strips unsupported values from setting" do
|
|
||||||
SiteSetting.content_security_policy_script_src =
|
|
||||||
"'unsafe-eval'|blob:|https://example.com/script.js"
|
|
||||||
|
|
||||||
script_src = parse(policy)["script-src"]
|
|
||||||
expect(script_src).to include("'unsafe-eval'")
|
|
||||||
expect(script_src).not_to include("blob:")
|
|
||||||
expect(script_src).not_to include("https://example.com/script.js")
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse(csp_string)
|
def parse(csp_string)
|
||||||
csp_string
|
csp_string
|
||||||
.split(";")
|
.split(";")
|
||||||
|
|
50
spec/lib/validators/csp_script_src_validator_spec.rb
Normal file
50
spec/lib/validators/csp_script_src_validator_spec.rb
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
RSpec.describe CspScriptSrcValidator do
|
||||||
|
describe "#valid_value?" do
|
||||||
|
context "when values are valid" do
|
||||||
|
context "when value is an empty string" do
|
||||||
|
it { is_expected.to be_a_valid_value "" }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when there's a single value" do
|
||||||
|
%w[
|
||||||
|
'unsafe-eval'
|
||||||
|
'wasm-unsafe-eval'
|
||||||
|
'sha256-valid_h4sH'
|
||||||
|
'sha384-valid-h4sH='
|
||||||
|
'sha512-valid+h4sH=='
|
||||||
|
].each { |valid_value| it { is_expected.to be_a_valid_value valid_value } }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when there are multiple valid values" do
|
||||||
|
let(:valid_values) do
|
||||||
|
%w[
|
||||||
|
'unsafe-eval'
|
||||||
|
'wasm-unsafe-eval'
|
||||||
|
'sha384-oqVuAfXRKap7fdgcCY5-ykM6+R9GqQ8K/uxy9rx_HNQlGYl1kPzQho1wx4JwY8wC'
|
||||||
|
].join("|")
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.to be_a_valid_value valid_values }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when values are invalid" do
|
||||||
|
context "when there's a single value" do
|
||||||
|
%w[
|
||||||
|
unsafe-eval
|
||||||
|
'unsafe-eval'!
|
||||||
|
!'unsafe-eval'
|
||||||
|
'sha256-not+a+valid+base64===='
|
||||||
|
'md5-not+a+supported+hash+algo'
|
||||||
|
'sha224-not+a+supported+hash+algo'
|
||||||
|
].each { |invalid_value| it { is_expected.not_to be_a_valid_value invalid_value } }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when there is at least 1 invalid value and 1 valid value" do
|
||||||
|
it { is_expected.not_to be_a_valid_value "'unsafe-eval'|'md5-not+a+supported+hash+algo'" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user