emk-safe_erb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006 Shinya Kasatani
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,37 @@
1
+ = Safe ERB
2
+
3
+ == Overview
4
+
5
+ Safe ERB lets you make sure that the string written by "<%= %>" in your rhtml template is escaped correctly. If you try to show the attributes in the ActiveRecord instance read from the database or the parameters received from the request without escaping them using "h" method, an exception will be raised. This will significantly reduce the possibility of putting cross-site scripting vulnerability into your web application.
6
+
7
+ The check is done using "tainted?" method in Object class which is a standard feature provided by Ruby - the string is "tainted" when it is read from IO. When ERB::Util#h method is called, this plugin "untaints" the string, and when "<%= %>" is called in your rhtml template, it raises an exception if the string you are trying to show is tainted.
8
+
9
+ == About this version of Safe ERB
10
+
11
+ This fork of Safe ERB has been modified to work with Mephisto under Rails 2.2. It may work with other Rails applications. Patches are welcome!
12
+
13
+ == Installation
14
+
15
+ Just put this plugin into vendor/plugins directory in your Rails application. No configuration is needed.
16
+
17
+ This version of Safe ERB has been tested with Mephisto under Rails 2.2. It has been tested with SQLite3, and there's a decent chance it should work with PostgreSQL and MySQL (and any other database which properly taints the data returned from the database).
18
+
19
+ == Details
20
+
21
+ The string becomes tainted when it is read from IO, such as the data read from the DB or HTTP request. However, the request parameters are not tainted in functional and integration tests, and also if your server is Mongrel. Hence this plugin installs before_filter into ActionController::Base that always taints request parameters and cookies.
22
+
23
+ The returned values from the following methods become untainted:
24
+
25
+ - ERB::Util#h
26
+ - ActionView::Helpers::TagHelper#escape
27
+ - ActionView::Helpers::TextHelper#strip_tags
28
+
29
+ Also, you can always untaint any string manually by calling "untaint" method (standard Ruby feature).
30
+
31
+ Several ActionView helpers have also been modified to untaint their return values. This is a temporary measure to get things working with Mephisto. See the source for details.
32
+
33
+ == Contact
34
+
35
+ The orignal safe_erb plugin was written by Shinya Kasatani <kasatani at gmail.com>.
36
+
37
+ This forked version was written by Eric Kidd, based on work by Matthew Bass.
data/Rakefile ADDED
@@ -0,0 +1,63 @@
1
+ require 'rubygems'
2
+ require 'rubygems/specification'
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/gempackagetask'
7
+
8
+ GEM = "safe_erb"
9
+ GEM_VERSION = "0.1.0"
10
+ SUMMARY = "Automatically detect improperty-escaped text in ERB templates"
11
+ AUTHORS = ["Shinya Kasatani", "Matthew Bass", "Eric Kidd"]
12
+ EMAIL = "git@randomhacks.net"
13
+ HOMEPAGE = "http://github.com/emk/safe_erb/tree/master"
14
+
15
+ spec = Gem::Specification.new do |s|
16
+ s.name = GEM
17
+ s.version = GEM_VERSION
18
+ s.platform = Gem::Platform::RUBY
19
+ s.summary = SUMMARY
20
+ s.require_paths = ['lib']
21
+ s.files = FileList['{lib,rails,test}/**/*.rb', '[A-Z]*'].to_a
22
+
23
+ s.authors = AUTHORS
24
+ s.email = EMAIL
25
+ s.homepage = HOMEPAGE
26
+
27
+ s.rubyforge_project = GEM # GitHub bug, gem isn't being build when this miss
28
+ end
29
+
30
+ desc 'Default: run unit tests.'
31
+ task :default => :test
32
+
33
+ desc 'Test the safe_erb plugin.'
34
+ Rake::TestTask.new(:test) do |t|
35
+ t.libs << 'lib'
36
+ t.pattern = 'test/**/*_test.rb'
37
+ t.verbose = true
38
+ end
39
+
40
+ desc 'Generate documentation for the safe_erb plugin.'
41
+ Rake::RDocTask.new(:rdoc) do |rdoc|
42
+ rdoc.rdoc_dir = 'rdoc'
43
+ rdoc.title = 'SafeERB'
44
+ rdoc.options << '--line-numbers' << '--inline-source'
45
+ rdoc.rdoc_files.include('README')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
48
+
49
+ Rake::GemPackageTask.new(spec) do |pkg|
50
+ pkg.gem_spec = spec
51
+ end
52
+
53
+ desc "Install the gem locally"
54
+ task :install => [:package] do
55
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
56
+ end
57
+
58
+ desc "Create a gemspec file"
59
+ task :make_spec do
60
+ File.open("#{GEM}.gemspec", "w") do |file|
61
+ file.puts spec.to_ruby
62
+ end
63
+ end
@@ -0,0 +1,20 @@
1
+ module ActionView
2
+ module TemplateHandlers
3
+ class ERB < TemplateHandler
4
+ def compile_with_safe_erb(template)
5
+ # This helps make new-style ActionMailer text templates do the
6
+ # right thing automatically. We will probably want to extend this
7
+ # to other kinds of templates eventually.
8
+ if template.filename.to_s =~ /\.text\.plain\.erb$/
9
+ ::ERB.without_checking_tainted do
10
+ compile_without_safe_erb template
11
+ end
12
+ else
13
+ compile_without_safe_erb template
14
+ end
15
+ end
16
+
17
+ alias_method_chain :compile, :safe_erb
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,51 @@
1
+ # SafeERB
2
+
3
+ require 'erb'
4
+ require 'action_controller'
5
+ require 'action_view'
6
+
7
+ class ActionController::Base
8
+ # Object#taint is set when the request comes from FastCGI or WEBrick,
9
+ # but it is not set in Mongrel and also functional / integration testing
10
+ # so we'll set it anyways in the filter
11
+ before_filter :taint_request
12
+
13
+ def render_with_taint_logic(*args, &blk)
14
+ if @skip_checking_tainted
15
+ ERB.without_checking_tainted do
16
+ render_without_taint_logic(*args, &blk)
17
+ end
18
+ else
19
+ render_without_taint_logic(*args, &blk)
20
+ end
21
+ end
22
+
23
+ alias_method_chain :render, :taint_logic
24
+
25
+ private
26
+
27
+ def taint_hash(hash)
28
+ hash.each do |k, v|
29
+ case v
30
+ when String
31
+ v.taint
32
+ when Hash
33
+ taint_hash(v)
34
+ end
35
+ end
36
+ end
37
+
38
+ def taint_request
39
+ taint_hash(params)
40
+ cookies.each do |k, v|
41
+ v.taint
42
+ end
43
+ end
44
+ end
45
+
46
+ class String
47
+ def concat_unless_tainted(str)
48
+ raise "attempted to output tainted string: #{str}" if str.is_a?(String) && str.tainted?
49
+ concat(str)
50
+ end
51
+ end
@@ -0,0 +1,52 @@
1
+ class ERB
2
+ # Should we check for tainted values when building ERB templates?
3
+ def self.check_tainted?
4
+ value = Thread.current[:safe_erb_check_tainted]
5
+ value.nil? ? true : value
6
+ end
7
+
8
+ # Turn ERB taint-checking on and off.
9
+ def self.check_tainted= value
10
+ Thread.current[:safe_erb_check_tainted] = value
11
+ end
12
+
13
+ # Skip taint checks within the specified block.
14
+ def self.without_checking_tainted #:yield:
15
+ saved_value = ERB.check_tainted?
16
+ ERB.check_tainted = false
17
+ begin
18
+ yield
19
+ ensure
20
+ ERB.check_tainted = saved_value
21
+ end
22
+ end
23
+
24
+ alias_method :original_set_eoutvar, :set_eoutvar
25
+
26
+ def set_eoutvar(compiler, eoutvar = '_erbout')
27
+ original_set_eoutvar(compiler, eoutvar)
28
+ if ERB.check_tainted?
29
+ if compiler.respond_to?(:insert_cmd)
30
+ compiler.insert_cmd = "#{eoutvar}.concat_unless_tainted"
31
+ else
32
+ compiler.put_cmd = "#{eoutvar}.concat_unless_tainted"
33
+ end
34
+ end
35
+ end
36
+
37
+ module Util
38
+ alias_method :html_escape_without_untaint, :html_escape
39
+
40
+ def html_escape(s)
41
+ h = html_escape_without_untaint(s)
42
+ h.untaint
43
+ h
44
+ end
45
+
46
+ alias_method :h, :html_escape
47
+
48
+ module_function :h
49
+ module_function :html_escape
50
+ module_function :html_escape_without_untaint
51
+ end
52
+ end
@@ -0,0 +1,11 @@
1
+ # Rails 1.x dependent code (tested on 1.2.6)
2
+
3
+ module ActionView::Helpers::TextHelper
4
+ alias_method :strip_tags_without_untaint, :strip_tags
5
+
6
+ def strip_tags(html)
7
+ str = strip_tags_without_untaint(html)
8
+ str.untaint
9
+ str
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # Rails 2.0 dependent code (tested on 2.0.2)
2
+
3
+ module ActionView::Helpers::SanitizeHelper
4
+ def strip_tags_with_untaint(html)
5
+ str = strip_tags_without_untaint(html)
6
+ str.untaint
7
+ str
8
+ end
9
+
10
+ alias_method_chain :strip_tags, :untaint
11
+ end
@@ -0,0 +1,18 @@
1
+ module SQLite3
2
+ class ResultSet
3
+ # Add taint to data returned from SQLite3 database. This is based on a
4
+ # patch by Koji Shimada:
5
+ # http://rubyforge.org/tracker/index.php?func=detail&aid=20325&group_id=254&atid=1045
6
+ def next_with_tainting
7
+ row = next_without_tainting
8
+ case row
9
+ when Hash
10
+ row.each {|key, value| value.taint }
11
+ when Array
12
+ row.each {|column| column.taint }
13
+ end
14
+ row
15
+ end
16
+ alias_method_chain :next, :tainting
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ module ActionView
2
+ module Helpers
3
+ module TagHelper
4
+ def escape_once_with_untaint(html)
5
+ escape_once_without_untaint(html).untaint
6
+ end
7
+
8
+ alias_method_chain :escape_once, :untaint
9
+ end
10
+
11
+ module DateHelper
12
+ # TODO - This is almost certainly too aggressive, and it will need to
13
+ # be fine-tuned.
14
+ def datetime_select_with_untaint(*args)
15
+ datetime_select_without_untaint(*args).untaint
16
+ end
17
+ alias_method_chain :datetime_select, :untaint
18
+ end
19
+
20
+ module ActiveRecordHelper
21
+ # TODO - This is almost certainly too aggressive, and it will need to
22
+ # be fine-tuned.
23
+ def error_messages_for_with_untaint(*args)
24
+ error_messages_for_without_untaint(*args).untaint
25
+ end
26
+ alias_method_chain :error_messages_for, :untaint
27
+ end
28
+ end
29
+ end
data/lib/safe_erb.rb ADDED
@@ -0,0 +1,16 @@
1
+ # SafeERB
2
+
3
+ require 'safe_erb/common'
4
+ require 'safe_erb/tag_helper'
5
+ require 'safe_erb/erb_extensions'
6
+ require 'safe_erb/action_view_extensions'
7
+
8
+ if Rails::VERSION::MAJOR >= 2
9
+ require 'safe_erb/rails_2'
10
+ else
11
+ require 'safe_erb/rails_1'
12
+ end
13
+
14
+ if ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)
15
+ require 'safe_erb/sqlite3_fix'
16
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require_dependency 'safe_erb'
@@ -0,0 +1,20 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+
3
+ class SafeERBTest < Test::Unit::TestCase
4
+ def test_non_checking
5
+ ERB.without_checking_tainted do
6
+ src = ERB.new("<%= File.open('#{__FILE__}'){|f| f.read} %>", nil, '-').src
7
+ eval(src)
8
+ end
9
+ end
10
+
11
+ def test_checking
12
+ src = ERB.new("<%= File.open('#{__FILE__}'){|f| f.read} %>", nil, '-').src
13
+ assert_raise(RuntimeError) { eval(src) }
14
+ end
15
+
16
+ def test_checking_non_tainted
17
+ src = ERB.new("<%= 'This string is not tainted' %>", nil, '-').src
18
+ eval(src)
19
+ end
20
+ end
@@ -0,0 +1,30 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+
3
+ class TagHelperTest < Test::Unit::TestCase
4
+ include ActionView::Helpers::TagHelper
5
+ include ActionView::Helpers::DateHelper
6
+ include ActionView::Helpers::ActiveRecordHelper
7
+
8
+ def test_inclusion_in_taghelper
9
+ assert self.respond_to?(:escape_once_with_untaint)
10
+ assert self.respond_to?(:escape_once_without_untaint)
11
+ end
12
+
13
+ def test_taghelper_untaints
14
+ evil_str = "evil knievel".taint
15
+ assert !escape_once(evil_str).tainted?
16
+ assert escape_once_without_untaint(evil_str).tainted?
17
+ end
18
+
19
+ Post = Struct.new(:published_at)
20
+ def post
21
+ @post ||= Post.new(Time.now.taint)
22
+ end
23
+
24
+ def test_datetime_select_should_untaint
25
+ assert !datetime_select(:post, :published_at).tainted?
26
+ end
27
+
28
+ # TODO - Add tests for error_messages_for helper. This is a little
29
+ # tricky, because we'll need an ActiveRecord::Base instance.
30
+ end
@@ -0,0 +1,9 @@
1
+ module Rails
2
+ module VERSION
3
+ MAJOR = 2.1
4
+ end
5
+ end
6
+
7
+ require 'rubygems'
8
+ require 'test/unit'
9
+ require 'safe_erb'
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: emk-safe_erb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Shinya Kasatani
8
+ - Matthew Bass
9
+ - Eric Kidd
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2008-12-16 00:00:00 -08:00
15
+ default_executable:
16
+ dependencies: []
17
+
18
+ description:
19
+ email: git@randomhacks.net
20
+ executables: []
21
+
22
+ extensions: []
23
+
24
+ extra_rdoc_files: []
25
+
26
+ files:
27
+ - lib/safe_erb/action_view_extensions.rb
28
+ - lib/safe_erb/common.rb
29
+ - lib/safe_erb/erb_extensions.rb
30
+ - lib/safe_erb/rails_1.rb
31
+ - lib/safe_erb/rails_2.rb
32
+ - lib/safe_erb/sqlite3_fix.rb
33
+ - lib/safe_erb/tag_helper.rb
34
+ - lib/safe_erb.rb
35
+ - rails/init.rb
36
+ - test/safe_erb_test.rb
37
+ - test/tag_helper_test.rb
38
+ - test/test_helper.rb
39
+ - MIT-LICENSE
40
+ - Rakefile
41
+ - README
42
+ has_rdoc: false
43
+ homepage: http://github.com/emk/safe_erb/tree/master
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project: safe_erb
64
+ rubygems_version: 1.2.0
65
+ signing_key:
66
+ specification_version: 2
67
+ summary: Automatically detect improperty-escaped text in ERB templates
68
+ test_files: []
69
+