From 0985552f331b572d72ad96ce06f03816da57340c Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Mon, 23 May 2011 10:07:54 +0200 Subject: [PATCH] initial commit --- rack-protection/.gitignore | 2 + rack-protection/Gemfile | 2 + rack-protection/License | 20 +++++++++ rack-protection/README.md | 17 +++++++ rack-protection/Rakefile | 37 ++++++++++++++++ rack-protection/lib/rack-protection.rb | 1 + rack-protection/lib/rack/protection.rb | 33 ++++++++++++++ .../lib/rack/protection/authenticity_token.rb | 8 ++++ rack-protection/lib/rack/protection/base.rb | 44 +++++++++++++++++++ .../lib/rack/protection/escaped_params.rb | 8 ++++ .../lib/rack/protection/form_token.rb | 8 ++++ .../lib/rack/protection/frame_options.rb | 8 ++++ .../lib/rack/protection/no_referrer.rb | 8 ++++ .../lib/rack/protection/path_traversal.rb | 8 ++++ .../lib/rack/protection/remote_referrer.rb | 8 ++++ .../lib/rack/protection/remote_token.rb | 8 ++++ .../lib/rack/protection/session_hihacking.rb | 8 ++++ .../lib/rack/protection/version.rb | 44 +++++++++++++++++++ .../lib/rack/protection/xss_header.rb | 21 +++++++++ rack-protection/rack-protection.gemspec | 35 +++++++++++++++ rack-protection/spec/rack_protection_spec.rb | 5 +++ 21 files changed, 333 insertions(+) create mode 100644 rack-protection/.gitignore create mode 100644 rack-protection/Gemfile create mode 100644 rack-protection/License create mode 100644 rack-protection/README.md create mode 100644 rack-protection/Rakefile create mode 100644 rack-protection/lib/rack-protection.rb create mode 100644 rack-protection/lib/rack/protection.rb create mode 100644 rack-protection/lib/rack/protection/authenticity_token.rb create mode 100644 rack-protection/lib/rack/protection/base.rb create mode 100644 rack-protection/lib/rack/protection/escaped_params.rb create mode 100644 rack-protection/lib/rack/protection/form_token.rb create mode 100644 rack-protection/lib/rack/protection/frame_options.rb create mode 100644 rack-protection/lib/rack/protection/no_referrer.rb create mode 100644 rack-protection/lib/rack/protection/path_traversal.rb create mode 100644 rack-protection/lib/rack/protection/remote_referrer.rb create mode 100644 rack-protection/lib/rack/protection/remote_token.rb create mode 100644 rack-protection/lib/rack/protection/session_hihacking.rb create mode 100644 rack-protection/lib/rack/protection/version.rb create mode 100644 rack-protection/lib/rack/protection/xss_header.rb create mode 100644 rack-protection/rack-protection.gemspec create mode 100644 rack-protection/spec/rack_protection_spec.rb diff --git a/rack-protection/.gitignore b/rack-protection/.gitignore new file mode 100644 index 00000000..3944b1b6 --- /dev/null +++ b/rack-protection/.gitignore @@ -0,0 +1,2 @@ +# please add general patterns to your global ignore list +# see https://github.com/github/gitignore#readme diff --git a/rack-protection/Gemfile b/rack-protection/Gemfile new file mode 100644 index 00000000..7f5eae31 --- /dev/null +++ b/rack-protection/Gemfile @@ -0,0 +1,2 @@ +source "http://rubygems.org" unless ENV['QUICK'] +gemspec diff --git a/rack-protection/License b/rack-protection/License new file mode 100644 index 00000000..858737cd --- /dev/null +++ b/rack-protection/License @@ -0,0 +1,20 @@ +Copyright (c) 2011 Konstantin Haase + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +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. diff --git a/rack-protection/README.md b/rack-protection/README.md new file mode 100644 index 00000000..7b28cae0 --- /dev/null +++ b/rack-protection/README.md @@ -0,0 +1,17 @@ +You should use protection! + +# Usage + +``` ruby +# config.ru +require 'rack/protection' +use Rack::Protection +``` + +# Installation + + gem install rack-protection + +# TODO + +* Write code and documentation diff --git a/rack-protection/Rakefile b/rack-protection/Rakefile new file mode 100644 index 00000000..b8ee58b3 --- /dev/null +++ b/rack-protection/Rakefile @@ -0,0 +1,37 @@ +$LOAD_PATH.unshift File.expand_path('../lib', __FILE__) + +begin + require 'bundler' + Bundler::GemHelper.install_tasks +rescue LoadError => e + $stderr.puts e +end + +desc "run specs" +task(:spec) { ruby '-S rspec spec' } + +desc "generate gemspec" +task 'rack-protection.gemspec' do + require 'rack/protection/version' + content = File.read 'rack-protection.gemspec' + + fields = { + :authors => `git shortlog -sn`.scan(/[^\d\s].*/), + :email => `git shortlog -sne`.scan(/[^<]+@[^>]+/), + :files => `git ls-files`.split("\n").reject { |f| f =~ /^(\.|Gemfile)/ } + } + + fields.each do |field, values| + updated = " s.#{field} = [" + updated << values.map { |v| "\n %p" % v }.join(',') + updated << "\n ]" + content.sub!(/ s\.#{field} = \[\n( .*\n)* \]/, updated) + end + + content.sub! /(s\.version.*=\s+).*/, "\\1\"#{Rack::Protection::VERSION}\"" + File.open('rack-protection.gemspec', 'w') { |f| f << content } +end + +task :gemspec => 'rack-protection.gemspec' +task :default => :spec +task :test => :spec diff --git a/rack-protection/lib/rack-protection.rb b/rack-protection/lib/rack-protection.rb new file mode 100644 index 00000000..1633086e --- /dev/null +++ b/rack-protection/lib/rack-protection.rb @@ -0,0 +1 @@ +require "rack/protection" diff --git a/rack-protection/lib/rack/protection.rb b/rack-protection/lib/rack/protection.rb new file mode 100644 index 00000000..eb7c8ff6 --- /dev/null +++ b/rack-protection/lib/rack/protection.rb @@ -0,0 +1,33 @@ +require 'rack/protection/version' +require 'rack' + +module Rack + module Protection + autoload :AuthenticityToken, 'rack/protection/authenticity_token' + autoload :Base, 'rack/protection/base' + autoload :EscapedParams, 'rack/protection/escaped_params' + autoload :FormToken, 'rack/protection/form_token' + autoload :FrameOptions, 'rack/protection/frame_options' + autoload :NoReferrer, 'rack/protection/no_referrer' + autoload :PathTraversal, 'rack/protection/path_traversal' + autoload :RemoteReferrer, 'rack/protection/remote_referrer' + autoload :RemoteToken, 'rack/protection/remote_token' + autoload :SessionHijacking, 'rack/protection/session_hihacking' + autoload :XSSHeader, 'rack/protection/xss_header' + + def self.new(app, options = {}) + # does not include: AuthenticityToken, FormToken and NoReferrer + except = Array options[:except] + Rack::Builder.new do + use EscapedParams, options unless except.include? :escaped_params + use FrameOptions, options unless except.include? :frame_options + use PathTraversal, options unless except.include? :path_traversal + use RemoteReferrer, options unless except.include? :remote_referrer + use RemoteToken, options unless except.include? :remote_token + use SessionHijacking, options unless except.include? :session_hihacking + use XSSHeader, options unless except.include? :xss_header + run app + end.to_app + end + end +end diff --git a/rack-protection/lib/rack/protection/authenticity_token.rb b/rack-protection/lib/rack/protection/authenticity_token.rb new file mode 100644 index 00000000..b9eca4f3 --- /dev/null +++ b/rack-protection/lib/rack/protection/authenticity_token.rb @@ -0,0 +1,8 @@ +require 'rack/protection' + +module Rack + module Protection + class AuthenticityToken < Base + end + end +end diff --git a/rack-protection/lib/rack/protection/base.rb b/rack-protection/lib/rack/protection/base.rb new file mode 100644 index 00000000..76d1b8cc --- /dev/null +++ b/rack-protection/lib/rack/protection/base.rb @@ -0,0 +1,44 @@ +require 'rack/protection' + +module Rack + module Protection + class Base + DEFAULT_OPTIONS = { :reaction => :drop_session, :logging => true } + attr_reader :app, :options + + def self.default_options(options) + define_method(:default_options) { super().merge(options) } + end + + def default_options + DEFAULT_OPTIONS + end + + def initialize(app, options = {}) + @app, @options = app, options.merge(default_options) + end + + def accepts?(env) + raise NotImplementedError, "#{self.class} implementation pending" + end + + def call(env) + unless accepts? env + result = send(options[:reaction], env) + return result if Array === result and result.size = 3 + end + app.call(env) + end + + def warn(env, message) + return unless options[:logging] + l = options[:logger] || env['rack.logger'] || ::Logger.new(env['rack.errors']) + l.warn(message) + end + + def drop_session(env) + env['rack.session'] = {} + end + end + end +end diff --git a/rack-protection/lib/rack/protection/escaped_params.rb b/rack-protection/lib/rack/protection/escaped_params.rb new file mode 100644 index 00000000..e37ae4d9 --- /dev/null +++ b/rack-protection/lib/rack/protection/escaped_params.rb @@ -0,0 +1,8 @@ +require 'rack/protection' + +module Rack + module Protection + class EscapedParams < Base + end + end +end diff --git a/rack-protection/lib/rack/protection/form_token.rb b/rack-protection/lib/rack/protection/form_token.rb new file mode 100644 index 00000000..7f29dd42 --- /dev/null +++ b/rack-protection/lib/rack/protection/form_token.rb @@ -0,0 +1,8 @@ +require 'rack/protection' + +module Rack + module Protection + class FormToken < AuthenticityToken + end + end +end diff --git a/rack-protection/lib/rack/protection/frame_options.rb b/rack-protection/lib/rack/protection/frame_options.rb new file mode 100644 index 00000000..70e1eae1 --- /dev/null +++ b/rack-protection/lib/rack/protection/frame_options.rb @@ -0,0 +1,8 @@ +require 'rack/protection' + +module Rack + module Protection + class FrameOptions < Base + end + end +end diff --git a/rack-protection/lib/rack/protection/no_referrer.rb b/rack-protection/lib/rack/protection/no_referrer.rb new file mode 100644 index 00000000..556b09be --- /dev/null +++ b/rack-protection/lib/rack/protection/no_referrer.rb @@ -0,0 +1,8 @@ +require 'rack/protection' + +module Rack + module Protection + class NoReferrer < Base + end + end +end diff --git a/rack-protection/lib/rack/protection/path_traversal.rb b/rack-protection/lib/rack/protection/path_traversal.rb new file mode 100644 index 00000000..fc367387 --- /dev/null +++ b/rack-protection/lib/rack/protection/path_traversal.rb @@ -0,0 +1,8 @@ +require 'rack/protection' + +module Rack + module Protection + class PathTraversal < Base + end + end +end diff --git a/rack-protection/lib/rack/protection/remote_referrer.rb b/rack-protection/lib/rack/protection/remote_referrer.rb new file mode 100644 index 00000000..69d102ab --- /dev/null +++ b/rack-protection/lib/rack/protection/remote_referrer.rb @@ -0,0 +1,8 @@ +require 'rack/protection' + +module Rack + module Protection + class RemoteReferrer < Base + end + end +end diff --git a/rack-protection/lib/rack/protection/remote_token.rb b/rack-protection/lib/rack/protection/remote_token.rb new file mode 100644 index 00000000..64eeafe1 --- /dev/null +++ b/rack-protection/lib/rack/protection/remote_token.rb @@ -0,0 +1,8 @@ +require 'rack/protection' + +module Rack + module Protection + class RemoteToken < AuthenticityToken + end + end +end diff --git a/rack-protection/lib/rack/protection/session_hihacking.rb b/rack-protection/lib/rack/protection/session_hihacking.rb new file mode 100644 index 00000000..cd9ff616 --- /dev/null +++ b/rack-protection/lib/rack/protection/session_hihacking.rb @@ -0,0 +1,8 @@ +require 'rack/protection' + +module Rack + module Protection + class SessionHijacking < Base + end + end +end diff --git a/rack-protection/lib/rack/protection/version.rb b/rack-protection/lib/rack/protection/version.rb new file mode 100644 index 00000000..8443369b --- /dev/null +++ b/rack-protection/lib/rack/protection/version.rb @@ -0,0 +1,44 @@ +module Rack + module Protection + def self.version + VERSION + end + + module VERSION + extend Comparable + + MAJOR = 0 + MINOR = 0 + TINY = 1 + SIGNATURE = [MAJOR, MINOR, TINY] + STRING = SIGNATURE.join '.' + + def self.major; MAJOR end + def self.minor; MINOR end + def self.tiny; TINY end + def self.to_s; STRING end + + def self.hash + STRING.hash + end + + def self.<=>(other) + other = other.split('.').map { |i| i.to_i } if other.respond_to? :split + SIGNATURE <=> Array(other) + end + + def self.inspect + STRING.inspect + end + + def self.respond_to?(meth, *) + meth.to_s !~ /^__|^to_str$/ and STRING.respond_to? meth unless super + end + + def self.method_missing(meth, *args, &block) + return super unless STRING.respond_to?(meth) + STRING.send(meth, *args, &block) + end + end + end +end diff --git a/rack-protection/lib/rack/protection/xss_header.rb b/rack-protection/lib/rack/protection/xss_header.rb new file mode 100644 index 00000000..e57ea576 --- /dev/null +++ b/rack-protection/lib/rack/protection/xss_header.rb @@ -0,0 +1,21 @@ +module Rack + module Protection + class XSSHeader + HEADERS = { + 'X-XSS-Protection' => '1; mode=block', + 'X-Frame-Options' => 'sameorigin' + } + + def initialize(app, options) + @app = app + @headers = HEADERS.merge(options[:xss_headers] || {}) + @headers.delete_if { |k,v| !v } + end + + def call(env) + status, headers, body = @app.call(env) + [status, @headers.merge(headers), body] + end + end + end +end diff --git a/rack-protection/rack-protection.gemspec b/rack-protection/rack-protection.gemspec new file mode 100644 index 00000000..9c8f80b3 --- /dev/null +++ b/rack-protection/rack-protection.gemspec @@ -0,0 +1,35 @@ +# Run `rake rack-protection.gemspec` to update the gemspec. +Gem::Specification.new do |s| + # general infos + s.name = "rack-protection" + s.version = "0.0.1" + s.description = "You should use protection!" + s.homepage = "http://github.com/rkh/rack-protection" + s.summary = s.description + + # generated from git shortlog -sn + s.authors = [ + "Konstantin Haase" + ] + + # generated from git shortlog -sne + s.email = [ + "konstantin.mailinglists@googlemail.com" + ] + + # generated from git ls-files + s.files = [ + "License", + "README.md", + "Rakefile", + "lib/rack-protection.rb", + "lib/rack/protection.rb", + "lib/rack/protection/version.rb", + "rack-protection.gemspec", + "spec/rack_protection_spec.rb" + ] + + # dependencies + s.add_dependency "rack" + s.add_development_dependency "rspec", "~> 2.0" +end diff --git a/rack-protection/spec/rack_protection_spec.rb b/rack-protection/spec/rack_protection_spec.rb new file mode 100644 index 00000000..d8913a67 --- /dev/null +++ b/rack-protection/spec/rack_protection_spec.rb @@ -0,0 +1,5 @@ +require 'rack/protection' + +describe Rack::Protection do + it "should behave" +end