Fortress
Implement the simple but powerful protection: close everything and open the access explecitely.
As of today, and as far as I know, all protection libraries are bases on the principle that all is open and you close when need which can leads to security holes in the case you've forgotten to close a route.
It's probabely better to refuse the access to a page where a user should be allowed to access it than allowing access to a page where a user should not be allowed to access and let him sees things he shouldn't.
Installation
Add this line to your application's Gemfile:
gem 'fortress'
And then execute:
$ bundle
Or install it yourself as:
$ gem install fortress
Usage
After having installed the gem, and started the server, all the routes are closed. At this moment your application is absoluetly un-usable so it's in the maximum secure mode ; )
Configuration
externals
When using a gem adding controllers to your application, like Devise, Fortress needs to be aware of them otherwise it will prevent access to them.
You can do this by using the externals
option within an initializer:
Fortress.configure do |config|
config.externals = %w(SessionsController)
end
Allow access to the root controller
The first action to take is to allow the root controller as it's the place
where the user will be redirected in case he tries to access a place where he
is not allowed to.
(he is redirected to the root_url
and a flash message :error
is displayed.)
Given the root controller of your application is the WelcomeController
then
you can allow to access it with the following:
class WelcomeController < ApplicationController
fortress_allow :all
def index
# ...
end
end
fortress_allow
is the only method you need to know. Giving the :all
argument as parameter revert the behavior to the default one: All is open for
this controller.
It's simple and easy to use in public controllers (no data with limited access)
but I highly recommend you to use it as less as possible.
Allow a specific action
Now you want to allow access to an action of another controller.
In the case you don't have specific need you can write the following:
class PostsController < ApplicationController
fortress_allow :index
def index
# ...
end
end
Allow all actions except one
Let's say you have a controller with 4 actions and you want to allow all of them except one.
You can specify each actions by hand:
class PostsController < ApplicationController
fortress_allow [:index, :show, :download]
def index; end
def show; end
def destroy; end
def download; end
end
Or you can combine :all
with :except
class PostsController < ApplicationController
fortress_allow :all, except: :destroy
def index; end
def show; end
def destroy; end
def download; end
end
Note: This reduce a little bit the security as if you add a new action to the controller and you haven't updated Fortress, the action will be allowed.
Allowing on condition
Finally you can use the :if
key in order to allow only when the condition is
true.
class PostsController < ApplicationController
fortress_allow :all, except: :destroy
fortress_allow :destroy, if: :is_admin?
def index; end
def show; end
def destroy; end
def download; end
private
def is_admin?
current_user.admin?
end
end
Detecting blocked controllers
It can be a little bit hard to find all the blocked controller in a big application.
I recommend you to use the following command:
$ tail -f log/*.log | grep prevent_access -B 5
You will see which controller is called and then blocked by the prevent_access! method from Fortress.
Contributing
- Fork it ( https://github.com/YourCursus/fortress/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request