flyerhzm / bullet

help to kill N+1 queries and unused eager loading
MIT License
7.06k stars 431 forks source link

Content Security Policy not properly detected in Rails #651

Open rbclark opened 1 year ago

rbclark commented 1 year ago

I currently have a content security policy setup in my application, however it is not detected by bullet (I am running v7.0.7 of bullet). In order to investigate I went ahead and put a breakpoint in the bullet loader and discovered the following:

➜ rails c
[21, 30] in ~/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/bullet-7.0.7/lib/bullet.rb
    21|   autoload :NotificationCollector, 'bullet/notification_collector'
    22| 
    23|   if defined?(Rails::Railtie)
    24|     class BulletRailtie < Rails::Railtie
    25|       initializer 'bullet.configure_rails_initialization' do |app|
=>  26|         debugger
    27|         if defined?(ActionDispatch::ContentSecurityPolicy::Middleware) && Rails.application.config.content_security_policy
    28|           app.middleware.insert_before ActionDispatch::ContentSecurityPolicy::Middleware, Bullet::Rack
    29|         else
    30|           app.middleware.use Bullet::Rack
=>#0    block {|app=#<Kp20::Application>|} in <class:BulletRailtie> at ~/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/bullet-7.0.7/lib/bullet.rb:26
  #1    [C] BasicObject#instance_exec at ~/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/railties-7.0.4.3/lib/rails/initializable.rb:32
  # and 32 frames (use `bt' command for all frames)
(ruby) Rails.application.config.content_security_policy
nil
(rdbg) c    # continue command
Loading development environment (Rails 7.0.4.3)
irb: warn: can't alias context from irb_context.
irb(main):001:0> Rails.application.config.content_security_policy
=> 
#<ActionDispatch::ContentSecurityPolicy:0x000000010b5864c8                         
 @directives=                                                                      
  {"default-src"=>["'self'", "https:"],                                            
   "font-src"=>["'self'", "https:"],                                               
   "img-src"=>["'self'", "https:", "data:"],                                       
   "object-src"=>["'none'"],                                                       
   "script-src"=>["'self'", "https:"],                                             
   "style-src"=>["'self'", "https:"]}>                                             
irb(main):002:0> 

based on this it looks like bullet is loading too early and is ill positioned to actually detect whether the CSP middleware is loaded. In order to try to fix I tried moving the bullet initializer before and after the CSP loader but to no avail.

If I modify the bullet code to always call app.middleware.insert_before ActionDispatch::ContentSecurityPolicy::Middleware, Bullet::Rack then everything works properly, which confirms the issue is the loader not being able to detect the CSP.

ryoung commented 10 months ago

@rbclark I'm running into the same problem - did you ever figure out a solution?

rbclark commented 10 months ago

I've been running with Bullet.skip_html_injection = true in order to avoid this. Unfortunately that means no alerts in the browser but that was the best I could find.

ryoung commented 10 months ago

Ok cool - thanks for the tip.

I think a reasonable fix would be to remove the && Rails.application.config.content_security_policy check in the code - I don't see any downsides of inserting the Bullet::Rack middleware before ActionDispatch::ContentSecurityPolicy::Middleware

baueric commented 10 months ago

Here's an alternative, add this to your config/environments/development.rb:

MyApp::Application.configure do
  ...
  config.content_security_policy { }
  ...
end

That will initialize an empty policy prior to bullet init which makes Rails.application.config.content_security_policy truthy. It still configs your real CSP afterwards so it seems to be safe.

tisba commented 1 week ago

I'm wondering if @baueric's solution ☝️ is still the recommended workaround.