Content Security Policy
This commit is contained in:
parent
c8bdec242e
commit
5b20919fb3
12 changed files with 133 additions and 29 deletions
|
@ -1,7 +1,8 @@
|
|||
RAILS_ENV=production
|
||||
RAILS_ENV=
|
||||
IMAP_SERVER=
|
||||
DEFAULT_FROM=
|
||||
SKEL_SUTTY=https://0xacab.org/sutty/skel.sutty.nl
|
||||
SUTTY=sutty.nl
|
||||
SUTTY=sutty.local
|
||||
SUTTY_WITH_PORT=sutty.local:3000
|
||||
REDIS_SERVER=
|
||||
REDIS_CLIENT=
|
||||
|
|
|
@ -4,9 +4,6 @@ module Api
|
|||
module V1
|
||||
# API
|
||||
class BaseController < ActionController::Base
|
||||
http_basic_authenticate_with name: ENV['HTTP_BASIC_USER'],
|
||||
password: ENV['HTTP_BASIC_PASSWORD']
|
||||
|
||||
protect_from_forgery with: :null_session
|
||||
respond_to :json
|
||||
end
|
||||
|
|
42
app/controllers/api/v1/csp_reports_controller.rb
Normal file
42
app/controllers/api/v1/csp_reports_controller.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V1
|
||||
# Recibe los reportes de Content Security Policy
|
||||
class CspReportsController < BaseController
|
||||
# Crea un reporte de CSP intercambiando los guiones medios por
|
||||
# bajos
|
||||
#
|
||||
# TODO: Aplicar rate_limit
|
||||
def create
|
||||
csp = CspReport.new(csp_report_params.to_h.map do |k, v|
|
||||
{ k.tr('-', '_') => v }
|
||||
end.inject(&:merge))
|
||||
|
||||
csp.id = SecureRandom.uuid
|
||||
csp.save
|
||||
|
||||
render json: {}, status: :created
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only#Violation_report_syntax
|
||||
def csp_report_params
|
||||
params.require(:'csp-report')
|
||||
.permit(:disposition,
|
||||
:referrer,
|
||||
:'blocked-uri',
|
||||
:'document-uri',
|
||||
:'effective-directive',
|
||||
:'original-policy',
|
||||
:'script-sample',
|
||||
:'status-code',
|
||||
:'violated-directive',
|
||||
:'line-number',
|
||||
:'column-number',
|
||||
:'source-file')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4,6 +4,9 @@ module Api
|
|||
module V1
|
||||
# API para sitios
|
||||
class SitesController < BaseController
|
||||
http_basic_authenticate_with name: ENV['HTTP_BASIC_USER'],
|
||||
password: ENV['HTTP_BASIC_PASSWORD']
|
||||
|
||||
def index
|
||||
render json: Site.all.order(:name).pluck(:name)
|
||||
end
|
||||
|
|
4
app/models/csp_report.rb
Normal file
4
app/models/csp_report.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Almacena un reporte de CSP
|
||||
class CspReport < ApplicationRecord; end
|
|
@ -6,31 +6,34 @@
|
|||
# For further information see the following documentation
|
||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
||||
|
||||
# Rails.application.config.content_security_policy do |policy|
|
||||
# policy.default_src :self, :https
|
||||
# policy.font_src :self, :https, :data
|
||||
# policy.img_src :self, :https, :data
|
||||
# policy.object_src :none
|
||||
# policy.script_src :self, :https
|
||||
# policy.style_src :self, :https
|
||||
# # If you are using webpack-dev-server then specify
|
||||
# # webpack-dev-server host
|
||||
# policy.connect_src :self, :https, "http://localhost:3035",
|
||||
# "ws://localhost:3035" if Rails.env.development?
|
||||
Rails.application.config.content_security_policy do |policy|
|
||||
policy.default_src :self
|
||||
# XXX: Varios scripts generan estilos en línea
|
||||
policy.style_src :self, :unsafe_inline
|
||||
# Repetimos la default para poder saber cuál es la política en falta
|
||||
policy.script_src :self
|
||||
policy.font_src :self
|
||||
# TODO: Permitimos cargar imágenes remotas?
|
||||
policy.img_src :self
|
||||
# Ya no usamos applets!
|
||||
policy.object_src :none
|
||||
if Rails.env.development?
|
||||
policy.connect_src :self,
|
||||
'http://localhost:3035',
|
||||
'ws://localhost:3035'
|
||||
end
|
||||
|
||||
# # Specify URI for violation reports
|
||||
# # policy.report_uri "/csp-violation-report-endpoint"
|
||||
# end
|
||||
# Specify URI for violation reports
|
||||
policy.report_uri "https://api.#{ENV.fetch('SUTTY_WITH_PORT', 'sutty.nl')}/v1/csp_reports.json"
|
||||
end
|
||||
|
||||
# If you are using UJS then enable automatic nonce generation
|
||||
# Rails.application.config.content_security_policy_nonce_generator =
|
||||
# -> request { SecureRandom.base64(16) }
|
||||
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
|
||||
|
||||
# Set the nonce only to specific directives
|
||||
# Rails.application.config.content_security_policy_nonce_directives =
|
||||
# %w(script-src)
|
||||
# Rails.application.config.content_security_policy_nonce_directives = %w(script-src)
|
||||
|
||||
# Report CSP violations to a specified URI
|
||||
# For further information see the following documentation:
|
||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
|
||||
# Rails.application.config.content_security_policy_report_only = true
|
||||
Rails.application.config.content_security_policy_report_only = false
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# Add new mime types for use in respond_to blocks:
|
||||
# Mime::Type.register "text/richtext", :rtf
|
||||
Mime::Type.register 'application/csp-report', :json
|
||||
|
|
|
@ -18,6 +18,7 @@ Rails.application.routes.draw do
|
|||
constraints subdomain: 'api' do
|
||||
scope module: 'api' do
|
||||
namespace :v1 do
|
||||
resources :csp_reports, only: %i[create]
|
||||
get 'sites/allowed', to: 'sites#allowed'
|
||||
resources :sites, only: %i[index]
|
||||
end
|
||||
|
|
17
db/migrate/20200205173039_create_csp_reports.rb
Normal file
17
db/migrate/20200205173039_create_csp_reports.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
class CreateCspReports < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
create_table :csp_reports, id: :uuid do |t|
|
||||
t.timestamps
|
||||
|
||||
t.string :disposition
|
||||
t.string :referrer
|
||||
t.string :blocked_uri
|
||||
t.string :document_uri
|
||||
t.string :effective_directive
|
||||
t.string :original_policy
|
||||
t.string :script_sample
|
||||
t.string :status_code
|
||||
t.string :violated_directive
|
||||
end
|
||||
end
|
||||
end
|
7
db/migrate/20200206151057_add_source_to_csp_reports.rb
Normal file
7
db/migrate/20200206151057_add_source_to_csp_reports.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
class AddSourceToCspReports < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
add_column :csp_reports, :column_number, :integer
|
||||
add_column :csp_reports, :line_number, :integer
|
||||
add_column :csp_reports, :source_file, :string
|
||||
end
|
||||
end
|
|
@ -12,7 +12,10 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20_190_829_180_743) do
|
||||
ActiveRecord::Schema.define(version: 20_200_206_151_057) do
|
||||
# Could not dump table "access_logs" because of following StandardError
|
||||
# Unknown type '' for column 'id'
|
||||
|
||||
create_table 'action_text_rich_texts', force: :cascade do |t|
|
||||
t.string 'name', null: false
|
||||
t.text 'body'
|
||||
|
@ -55,6 +58,9 @@ ActiveRecord::Schema.define(version: 20_190_829_180_743) do
|
|||
t.index ['deploy_id'], name: 'index_build_stats_on_deploy_id'
|
||||
end
|
||||
|
||||
# Could not dump table "csp_reports" because of following StandardError
|
||||
# Unknown type 'uuid' for column 'id'
|
||||
|
||||
create_table 'deploys', force: :cascade do |t|
|
||||
t.datetime 'created_at', null: false
|
||||
t.datetime 'updated_at', null: false
|
||||
|
@ -132,6 +138,7 @@ ActiveRecord::Schema.define(version: 20_190_829_180_743) do
|
|||
t.string 'status', default: 'waiting'
|
||||
t.text 'description'
|
||||
t.string 'title'
|
||||
t.boolean 'colaboracion_anonima', default: false
|
||||
t.index ['design_id'], name: 'index_sites_on_design_id'
|
||||
t.index ['licencia_id'], name: 'index_sites_on_licencia_id'
|
||||
t.index ['name'], name: 'index_sites_on_name', unique: true
|
||||
|
|
25
test/controllers/api/v1/csp_reports_controller_test.rb
Normal file
25
test/controllers/api/v1/csp_reports_controller_test.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'test_helper'
|
||||
|
||||
module Api
|
||||
module V1
|
||||
class CSPReportsControllerTest < ActionDispatch::IntegrationTest
|
||||
test 'se puede enviar un reporte' do
|
||||
post v1_csp_reports_url,
|
||||
params: {
|
||||
'csp-report': {
|
||||
'document-uri': 'http://example.com/signup.html',
|
||||
'referrer': '',
|
||||
'blocked-uri': 'http://example.com/css/style.css',
|
||||
'violated-directive': 'style-src cdn.example.com',
|
||||
'original-policy': "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports"
|
||||
}
|
||||
}
|
||||
|
||||
assert_equal 201, response.status
|
||||
assert_equal 1, CspReport.all.count
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue