forked from decidim/decidim
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Content Security Policy support (decidim#10700)
* Add Content Security Policy concern * Add inclusion of Concern * Add CSP settings * Refactor * Extract CSP in own class * Running linters, add Headers module * Add documentation, value to initializer * Fix failing specs * Apply review Recommendations * Update the documentation links * Apply suggestions from code review Co-authored-by: Andrés Pereira de Lucena <[email protected]> * Remove jsdeliver * Apply review recommendations * Update the documentation readme * Running linters * Revert jsdeliver.net * Fix invalid rule spec * Fixing code review bug * Apply suggestions from code review Co-authored-by: Andrés Pereira de Lucena <[email protected]> * Comply with the latest changes * Change the documentation * Lock sass-embedded * Add guard clause --------- Co-authored-by: Andrés Pereira de Lucena <[email protected]>
- Loading branch information
1 parent
c7db070
commit 2a12210
Showing
36 changed files
with
709 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
decidim-core/app/controllers/concerns/decidim/headers/content_security_policy.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# frozen_string_literal: true | ||
|
||
require "active_support/concern" | ||
|
||
module Decidim | ||
module Headers | ||
module ContentSecurityPolicy | ||
extend ActiveSupport::Concern | ||
|
||
included do | ||
def content_security_policy | ||
@content_security_policy ||= Decidim::ContentSecurityPolicy.new(current_organization, Decidim.content_security_policies_extra) | ||
end | ||
|
||
after_action :append_content_security_policy_headers | ||
end | ||
|
||
private | ||
|
||
def append_content_security_policy_headers | ||
response.headers["Content-Security-Policy"] = content_security_policy.output_policy | ||
end | ||
end | ||
end | ||
end |
23 changes: 23 additions & 0 deletions
23
decidim-core/app/controllers/concerns/decidim/headers/http_caching_disabler.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# frozen_string_literal: true | ||
|
||
require "active_support/concern" | ||
|
||
module Decidim | ||
module Headers | ||
# This module will disable http caching from the controller in | ||
# order to prevent proxies from storing sensible information. | ||
module HttpCachingDisabler | ||
extend ActiveSupport::Concern | ||
|
||
included do | ||
before_action :disable_http_caching | ||
end | ||
|
||
def disable_http_caching | ||
response.headers["Pragma"] = "no-cache" | ||
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT" | ||
response.cache_control.replace(no_cache: true, extras: ["no-store"]) | ||
end | ||
end | ||
end | ||
end |
21 changes: 0 additions & 21 deletions
21
decidim-core/app/controllers/concerns/decidim/http_caching_disabler.rb
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
decidim-core/db/migrate/20230409123300_add_content_policy_to_decidim_organizations.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# frozen_string_literal: true | ||
|
||
class AddContentPolicyToDecidimOrganizations < ActiveRecord::Migration[6.1] | ||
def change | ||
add_column :decidim_organizations, :content_security_policy, :jsonb, default: {} | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
# frozen_string_literal: true | ||
|
||
module Decidim | ||
# This class is responsible of generating the Content-Security-Policy header | ||
# for the application. It takes into account the organization's CSP settings | ||
# and the additional settings defined in the initializer. | ||
class ContentSecurityPolicy | ||
SUPPORTED_POLICIES = %w( | ||
child-src | ||
connect-src | ||
default-src | ||
font-src | ||
frame-src | ||
img-src | ||
manifest-src | ||
media-src | ||
object-src | ||
prefetch-src | ||
script-src | ||
script-src-elem | ||
script-src-attr | ||
style-src-elem | ||
style-src-attr | ||
worker-src | ||
base-uri | ||
sandbox | ||
form-action | ||
frame-ancestors | ||
navigate-to | ||
report-uri | ||
report-to | ||
require-trusted-types-for | ||
trusted-types | ||
upgrade-insecure-requests | ||
style-src | ||
).freeze | ||
|
||
def initialize(organization = nil, additional_policies = {}) | ||
@organization = organization | ||
@policy = default_policy | ||
@additional_policies = additional_policies | ||
end | ||
|
||
def output_policy | ||
add_system_csp_directives | ||
add_additional_policies | ||
organization_csp_directives | ||
append_development_directives | ||
|
||
format_policies | ||
end | ||
|
||
def append_csp_directive(directive, value) | ||
return if value.blank? | ||
|
||
message = "Invalid Content Security Policy directive: #{directive}, supported directives: #{SUPPORTED_POLICIES.join(", ")}" | ||
raise message unless SUPPORTED_POLICIES.include?(directive) | ||
|
||
policy[directive] ||= [] | ||
policy[directive] << value | ||
end | ||
|
||
private | ||
|
||
attr_reader :policy, :organization, :additional_policies | ||
|
||
def append_development_directives | ||
return unless Rails.env.development? | ||
|
||
host = ::Webpacker.config.dev_server[:host] | ||
port = ::Webpacker.config.dev_server[:port] | ||
|
||
append_csp_directive("connect-src", "wss://#{host}:#{port}") | ||
append_csp_directive("connect-src", "ws://#{host}:#{port}") | ||
end | ||
|
||
def format_policies | ||
policy.map do |directive, values| | ||
[directive, values.uniq.join(" ")].join(" ") | ||
end.join("; ") | ||
end | ||
|
||
def append_multiple_csp_directives(directive, values) | ||
values.each do |v| | ||
append_csp_directive(directive, v) | ||
end | ||
end | ||
|
||
def add_additional_policies | ||
additional_policies.each do |directive, values| | ||
next if values.blank? | ||
|
||
values = values.split if values.is_a?(String) | ||
|
||
raise "Invalid value for additional CSP policy #{directive}: #{values.inspect}" unless values.is_a?(Array) | ||
|
||
append_multiple_csp_directives(directive, values) | ||
end | ||
end | ||
|
||
def organization_csp_directives | ||
return unless organization | ||
|
||
organization.content_security_policy.each do |directive, value| | ||
append_multiple_csp_directives(directive, value.split) if value.present? | ||
end | ||
end | ||
|
||
def add_system_csp_directives | ||
return unless Rails.configuration.action_controller.asset_host | ||
|
||
%w(media-src img-src script-src style-src).each do |directive| | ||
append_csp_directive(directive, Rails.configuration.action_controller.asset_host) | ||
end | ||
end | ||
|
||
# rubocop:disable Lint/PercentStringArray | ||
def default_policy | ||
{ | ||
"default-src" => %w('self' 'unsafe-inline'), | ||
"script-src" => %w('self' 'unsafe-inline' 'unsafe-eval'), | ||
"style-src" => %w('self' 'unsafe-inline'), | ||
"img-src" => %w('self' *.hereapi.com data:), | ||
"font-src" => %w('self'), | ||
"connect-src" => %w('self' *.hereapi.com *.jsdelivr.net), | ||
"frame-src" => %w('self'), | ||
"media-src" => %w('self') | ||
} | ||
end | ||
# rubocop:enable Lint/PercentStringArray | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.