TL;DR; if you just want the code, head over to the bottom of this article
I noticed something odd with Active Storage direct uploads. Did you know there is literally no authentication at all by default! The idea scared me.
From the docs, it doesn’t say how to secure that endpoint either. There’s a way to use token auth for API apps but for traditional apps that’s still pretty much open season.
Let’s look at how that can be problematic, First we have CSRF protection so no one can just fire up curl and start uploading files from a script, however that can be easily solved by first making a legit request, grabbing the CSRF token and voila! We also have security by obfuscation assuming that a malicious actor doesn’t know that active storage uploads exists but I’m sure they can read the same documentation that you and I know read.
Someone can just spam upload large files and offset your S3 bill or simply run you out of storage, or DDOS your server all of which are not desirable scenarios.
To solve, this I found some GitHub issues that discussed this but no one provided a solution for what I was worried about, I saw an article from this guy but his solution suggested extending the ActiveStorge::DirectUploadsController
and creating a new route. This doesn’t really solve the problem because the other active storage direct uploads route will still be unprotected, I took his solution and used a much simpler implementation using an initializer.
Basically, we want
authenticate the direct uploads endpoint with a before_action
rate limit the endpoint to prevent DDOS
# config/initializers/active_storage.rb
Rails.application.config.to_prepare do
ActiveStorage::DirectUploadsController.class_eval do
before_action :authenticate_user!
rate_limit to: 20, within: 20.minutes, by: -> { current_user.id }
end
end
Rails has a configuration hook, at least that’s what I think that is, that allows you to run code before the rails app boots I imagine. The cool thing is, we can do a class_eval
on the ActiveStorage::DirectUploadsController
to add a before_action to authenticate the user then rate limit by user id so that one user doesn’t just spam upload files to the server.
Top comments (2)
It would be nice to show error message to the user without a page redirect.
It's possible, with direct uploads, and stimulus you can show errors, I'm using this with dropzone