Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert to gem #5

Merged
merged 2 commits into from Feb 25, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 17 additions & 1 deletion .gitignore
@@ -1 +1,17 @@
.redcar/**
*.gem
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
4 changes: 4 additions & 0 deletions Gemfile
@@ -0,0 +1,4 @@
source 'https://rubygems.org'

# Specify your gem's dependencies in session_protector2.gemspec
gemspec
6 changes: 4 additions & 2 deletions MIT-LICENSE → LICENSE.txt
@@ -1,4 +1,6 @@
Copyright (c) 2010 [name of plugin creator]
Copyright (c) 2013 Bonias

MIT License

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
Expand All @@ -17,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 changes: 11 additions & 5 deletions README.md
Expand Up @@ -9,21 +9,27 @@ DESCRIPTION
**WARNING:** this only makes a little bit harder to hijack user session, our solution basically have nothing to do with session security!!


Logout user if HTTP_USER_AGENT and IP differs from the one saved in session. This make it harder to successfully use session hijacking tools like [firesheep](http://codebutler.com/firesheep).
Clear session if HTTP_USER_AGENT and IP differs from the one saved in session. This make it harder to successfully use session hijacking tools like [firesheep](http://codebutler.com/firesheep).

Also, usage of `browser_fingerprint.js` allows usage of pseudo-unique fingerprint of users browser details. Both combined makes much harder (at least for script kiddies using firesheep for evil purposes) to hijack session (yeah, right).

REQUIREMENTS
------------

**Devise** or other authentication system based on **Warden**
**Rails**

INSTALL
-------

`rails plugin install git://github.com/galdomedia/session_protector.git`
add

You MAY also want to install browser_fingerprint script. To do this simply run:
`gem 'session_protector'`

to Gemfile and run

`bundle install`

You MAY also want to install browser_fingerprint script. To do this simply:

`rails generate session_protector:install`

Expand Down Expand Up @@ -68,4 +74,4 @@ CREDITS
* [Kevin van Zonneveld](http://phpjs.org/functions/md5:469) - JavaScript MD5


Copyright (c) 2010 Piotr Boniecki (piotr [at] galdomedia [dot] pl), released under the MIT license
Copyright (c) 2010 Piotr Boniecki (piotr [at] galdomedia [dot] pl), released under the MIT license
25 changes: 5 additions & 20 deletions Rakefile
@@ -1,23 +1,8 @@
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require "bundler/gem_tasks"

desc 'Default: run unit tests.'
task :default => :test
require 'rspec/core/rake_task'

desc 'Test the session_protector plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
RSpec::Core::RakeTask.new('spec')

desc 'Generate documentation for the session_protector plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'SessionProtector'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end
# If you want to make this the default task
task :default => :spec
2 changes: 0 additions & 2 deletions init.rb

This file was deleted.

1 change: 0 additions & 1 deletion install.rb

This file was deleted.

26 changes: 4 additions & 22 deletions lib/generators/session_protector/install_generator.rb
@@ -1,27 +1,9 @@
module SessionProtector
class InstallGenerator < Rails::Generators::Base
source_root File.expand_path("../../../../app/assets/javascripts", __FILE__)

FILES = [
'browser_fingerprint.js'
]

desc "Copy session_protector files to public/javascript folder."

source_root File.expand_path('../templates', __FILE__)

def install_session_protector
src_prefix = File.join('javascripts')
dest_prefix = File.join('public', 'javascripts')

FILES.each do |path|
src = File.join(src_prefix, path)
dest = File.join(dest_prefix, path)

copy_file(src, dest) if path =~ /\./
end

def copy_browser_fingerprint
copy_file "browser_fingerprint.js", "app/assets/javascripts/browser_fingerprint.js"
end

end

end
end
23 changes: 23 additions & 0 deletions lib/rack/session_protector.rb
@@ -0,0 +1,23 @@
require 'session_protector/base'

module Rack
class SessionProtector

def initialize(app, options={})
@options = {:check_ip => ::SessionProtector.check_ip}.merge(options)
@app = app
end

def call(env)
@request = ActionDispatch::Request.new(env)
protector = ::SessionProtector::Base.new(@request, @options)
if protector.safe_request?
@app.call(env)
else
@request.reset_session
[302, {"Location" => "/"}, []]
end
end

end
end
15 changes: 12 additions & 3 deletions lib/session_protector.rb
@@ -1,11 +1,20 @@
require "session_protector/version"

module SessionProtector
VERSION = '0.0.1'

# Check IP. True by default
mattr_accessor :check_ip
def self.check_ip
@@check_ip
end

def self.check_ip= attr
@@check_ip = attr
end

@@check_ip = true

def self.setup
yield self
end
end

require 'session_protector/rails'
81 changes: 39 additions & 42 deletions lib/session_protector/base.rb
@@ -1,64 +1,61 @@
module SessionProtector
class Error < StandardError

end

class Base
CHECK_METHODS = %w(cookie env_vars)

attr_accessor :warden, :scope, :session

def initialize(warden, scope)
@warden = warden
@scope = scope
@session = warden.session(scope)
end

def protect

attr_accessor :cookies, :session, :options, :request

def initialize(request, options)
@request = request
@session = @request.session
@cookies = @request.cookies
@options = options
end

def safe_request?
CHECK_METHODS.each do |method|
self.send("set_#{method}")
self.send("check_#{method}")
end
CHECK_METHODS.inject(false) do |logged_out, method|
logged_out || self.send("check_#{method}")

CHECK_METHODS.each do |method|
self.send("set_#{method}")
end
end


true
rescue ::SessionProtector::Error => e
false
end

private

def cookie_required_string
return @cookie_required_string if @cookie_required_string
cookies = warden.request.cookies
if cookies and cookies.keys.member?('_browser_fingerprint')
@cookie_required_string = cookies['_browser_fingerprint']
end
@cookie_required_string
@cookie_required_string ||= cookies['_browser_fingerprint']
end

def set_cookie
session['browser_fingerprint'] ||= cookie_required_string if cookie_required_string.present?
end

def check_cookie
if cookie_required_string != session['browser_fingerprint']
warden.logout(scope)
return true
end
return if session['browser_fingerprint'].nil?
raise ::SessionProtector::Error, "Wrong browser_fingerprint: #{cookie_required_string} != #{session['browser_fingerprint']}" if cookie_required_string == session['browser_fingerprint']
end

def env_vars_required_string
return @env_vars_required_string if @env_vars_required_string
if !warden.env['HTTP_USER_AGENT'].nil?
@env_vars_required_string = "#{warden.env['HTTP_USER_AGENT']}-#{SessionProtector.check_ip ? warden.request.remote_ip : ''}"
end
@env_vars_required_string
@env_vars_required_string ||= "#{request.env['HTTP_USER_AGENT']}-#{options[:check_ip] ? request.remote_ip : ''}"
end

def set_env_vars
session['user_agent_with_ip'] ||= env_vars_required_string if env_vars_required_string
end

def check_env_vars
if env_vars_required_string
if env_vars_required_string != session['user_agent_with_ip']
warden.logout(scope)
return true
end
end
return if session['user_agent_with_ip'].nil?
raise ::SessionProtector::Error, "Wrong user_agent_with_ip: #{env_vars_required_string} != #{session['user_agent_with_ip']}" if env_vars_required_string != session['user_agent_with_ip']
end

end
end
10 changes: 10 additions & 0 deletions lib/session_protector/rails.rb
@@ -0,0 +1,10 @@
require "rack/session_protector"
require 'rails'

module SessionProtector

class Engine < Rails::Engine
config.app_middleware.use Rack::SessionProtector
end

end
3 changes: 3 additions & 0 deletions lib/session_protector/version.rb
@@ -0,0 +1,3 @@
module SessionProtector
VERSION = "0.1.1"
end
4 changes: 0 additions & 4 deletions lib/warden/callback.rb

This file was deleted.

25 changes: 25 additions & 0 deletions session_protector.gemspec
@@ -0,0 +1,25 @@
# -*- encoding: utf-8 -*-
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'session_protector/version'

Gem::Specification.new do |gem|
gem.name = "session_protector"
gem.version = SessionProtector::VERSION
gem.authors = ["Piotr Boniecki", "GaldoMedia"]
gem.email = ["piotr@galdomedia.pl"]
gem.description = %q{Small middleware, that helps a little bit to protect user session from session hijacking (by checking browsers user_agent)}
gem.summary = %q{Small middleware, that helps a little bit to protect user session from session hijacking (by checking browsers user_agent)}
gem.homepage = "https://github.com/galdomedia/session_protector"
gem.license = "MIT"

gem.files = `git ls-files`.split($/)
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
gem.require_paths = ["lib"]

gem.add_dependency "rails"

gem.add_development_dependency "rake"
gem.add_development_dependency "rspec"
end
8 changes: 8 additions & 0 deletions spec/session_protector_spec.rb
@@ -0,0 +1,8 @@
require 'spec_helper'

describe SessionProtector do
it 'should have a version number' do
SessionProtector::VERSION.should_not be_nil
end

end
2 changes: 2 additions & 0 deletions spec/spec_helper.rb
@@ -0,0 +1,2 @@
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
require 'session_protector'
1 change: 0 additions & 1 deletion uninstall.rb

This file was deleted.