rack-cleanser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.0
5
+ before_install: gem install bundler -v 1.15.2
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at open.source@ribose.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ # (c) Copyright 2017 Ribose Inc.
2
+ #
3
+
4
+ source "https://rubygems.org"
5
+
6
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
7
+
8
+ # Specify your gem's dependencies in rack-cleanser.gemspec
9
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Ribose Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,57 @@
1
+ = Rack::Cleanser
2
+ :source-highlighter: pygments
3
+ :pygments-style: native
4
+ :pygments-linenums-mode: inline
5
+
6
+ image:https://img.shields.io/gem/v/rack-cleanser.svg["Gem Version", link="https://rubygems.org/gems/rack-cleanser"]
7
+ image:https://img.shields.io/travis/riboseinc/rack-cleanser/master.svg["Build Status", link="https://travis-ci.org/riboseinc/rack-cleanser"]
8
+ image:https://img.shields.io/codeclimate/github/riboseinc/rack-cleanser.svg["Code Climate", link="https://codeclimate.com/github/riboseinc/rack-cleanser"]
9
+
10
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rack/cleanser`. To experiment with that code, run `bin/console` for an interactive prompt.
11
+
12
+ TODO: Delete this and the text above, and describe your gem
13
+
14
+ == Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ [source,ruby]
19
+ ----
20
+ gem 'rack-cleanser'
21
+ ----
22
+
23
+ And then execute:
24
+
25
+ [source,sh]
26
+ ----
27
+ $ bundle
28
+ ----
29
+
30
+ Or install it yourself as:
31
+
32
+ [source,sh]
33
+ ----
34
+ $ gem install rack-cleanser
35
+ ----
36
+
37
+ == Usage
38
+
39
+ TODO: Write usage instructions here
40
+
41
+ == Development
42
+
43
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
44
+
45
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to https://rubygems.org[rubygems.org].
46
+
47
+ == Contributing
48
+
49
+ Bug reports and pull requests are welcome on GitHub at https://github.com/riboseinc/rack-cleanser. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the http://contributor-covenant.org[Contributor Covenant] code of conduct.
50
+
51
+ == License
52
+
53
+ The gem is available as open source under the terms of the http://opensource.org/licenses/MIT[MIT License].
54
+
55
+ == Code of Conduct
56
+
57
+ Everyone interacting in the Rack::Cleanser project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the https://github.com/riboseinc/rack-cleanser/blob/master/CODE_OF_CONDUCT.md[code of conduct].
@@ -0,0 +1,12 @@
1
+ # (c) Copyright 2017 Ribose Inc.
2
+ #
3
+
4
+ # Hashrocket style looks better when describing task dependencies.
5
+ # rubocop:disable Style/HashSyntax
6
+
7
+ require "bundler/gem_tasks"
8
+ require "rspec/core/rake_task"
9
+
10
+ RSpec::Core::RakeTask.new(:spec)
11
+
12
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rack/cleanser"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,76 @@
1
+ # (c) Copyright 2017 Ribose Inc.
2
+ #
3
+
4
+ require "rack"
5
+ require "rack/cleanser/version"
6
+ require "forwardable"
7
+ require "json"
8
+ require "pp"
9
+
10
+ module Rack
11
+ class Cleanser
12
+ autoload :ParamLengthLimiter, "rack/cleanser/param_length_limiter"
13
+ autoload :InvalidURIEncoding, "rack/cleanser/invalid_uri_encoding"
14
+
15
+ class << self
16
+ attr_accessor :oversize_response
17
+
18
+ def limit_param_length(name, options = {}, &block)
19
+ param_length_limits[name] = ParamLengthLimiter.new(name, options, block)
20
+ end
21
+
22
+ def filter_bad_uri_encoding
23
+ @want_uri_encoding_filtering = true
24
+ end
25
+
26
+ def param_length_limits
27
+ @param_length_limits ||= {}
28
+ end
29
+
30
+ def filter_bad_uri_encoding!(env)
31
+ InvalidURIEncoding.new[env] if @want_uri_encoding_filtering
32
+ end
33
+
34
+ def limit_param_length!(env)
35
+ param_length_limits.each do |_name, limit|
36
+ limit[env]
37
+ end
38
+ end
39
+
40
+ def clear!
41
+ @want_uri_encoding_filtering = false
42
+ @param_length_limits = {}
43
+ end
44
+
45
+ def cleanse!(env)
46
+ limit_param_length!(env)
47
+ filter_bad_uri_encoding!(env)
48
+ end
49
+ end
50
+
51
+ def initialize(app)
52
+ @app = app
53
+ end
54
+
55
+ @oversize_response = lambda { |_env, exn|
56
+ [
57
+ 413,
58
+ { "Content-Type" => "application/json" },
59
+ [{
60
+ error_message: "Request entity too large, #{exn.message}",
61
+ }.to_json],
62
+ ]
63
+ }
64
+
65
+ def call(env)
66
+ cleanse!(env)
67
+ @app.call(env)
68
+ rescue RequestTooLargeException => e
69
+ self.class.oversize_response.call(env, e)
70
+ end
71
+
72
+ extend Forwardable
73
+ def_delegators self,
74
+ :cleanse!
75
+ end
76
+ end
@@ -0,0 +1,96 @@
1
+ # (c) Copyright 2017 Ribose Inc.
2
+ #
3
+
4
+ # This is a middleware to check for invalid user's request path and request
5
+ # parameters.
6
+ module Rack
7
+ class Cleanser
8
+ class InvalidURIEncoding
9
+ # General Checking for user's input params
10
+ # throw 404 if params contain abnormal input
11
+ def check_encoding(query)
12
+ # make sure all params have valid encoding
13
+ all_values_for_hash(query).each do |param|
14
+ if param.respond_to?(:valid_encoding?) && !param.valid_encoding?
15
+ return :bad_encoding
16
+ end
17
+ end
18
+ end
19
+
20
+ def check_nested(query)
21
+ Rack::Utils.parse_nested_query(query)
22
+ rescue
23
+ :bad_query
24
+ end
25
+
26
+ # to get all values from a nested hash (i.e a hash contains hashes/arrays)
27
+ # e.g. {:a => 1, :b => {:ba => 2, :bb => [3, 4]}} gives you [1, 2, 3, 4]
28
+ def all_values_for_hash(hash)
29
+ result = []
30
+ hash.values.each do |hash_value|
31
+ case hash_value
32
+ when Hash
33
+ result += all_values_for_hash(hash_value)
34
+ when Array
35
+ # convert the array to hash
36
+ sub_hash = Hash[
37
+ hash_value.flatten.map.with_index do |value, index|
38
+ [index, value]
39
+ end
40
+ ]
41
+ result += all_values_for_hash(sub_hash)
42
+ else
43
+ result << hash_value
44
+ end
45
+ end
46
+ result
47
+ end
48
+
49
+ def [](env)
50
+ # Check and clean up trailing % characters by replacing them with their
51
+ # encoded equivalent %25
52
+ %w[
53
+ HTTP_REFERER
54
+ PATH_INFO
55
+ QUERY_STRING
56
+ REQUEST_PATH
57
+ REQUEST_URI
58
+ HTTP_X_FORWARDED_HOST
59
+ ].each do |key|
60
+ unless /\A(?:%[0-9a-fA-F]{2}|[^%])*\z/.match?(env[key].to_s)
61
+ env[key] = env[key].gsub(/%(?![0-9a-fA-F]{2})/, "%25")
62
+ end
63
+ raise_404_error if check_nested(env[key]) == :bad_query
64
+ end
65
+
66
+ # use these methods to get params as there is conflict with openresty
67
+ # request_params = Rack::Request.new(env).params
68
+ post_params = {}
69
+
70
+ post_params = if env["CONTENT_TYPE"].match?(%r{\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?}n)
71
+ {}
72
+ else
73
+ Rack::Utils.parse_query(env["rack.input"].read, "&")
74
+ end
75
+
76
+ get_params = Rack::Utils.parse_query(env["QUERY_STRING"], "&")
77
+ request_params = {}.merge(get_params).merge(post_params)
78
+
79
+ # Because env['rack.input'] is String IO object, so we need to rewind
80
+ # that to ensure it can be read again by others.
81
+ env["rack.input"].rewind
82
+
83
+ raise_404_error if check_encoding(request_params) == :bad_encoding
84
+
85
+ # make sure the authenticity token is a string
86
+ request_params.keys.each do |key|
87
+ raise_404_error if key.match?(/\Aauthenticity_token\[(.)*\]\z/)
88
+ end
89
+ end
90
+
91
+ def raise_404_error
92
+ raise ActionController::RoutingError.new("Not Found")
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,73 @@
1
+ # (c) Copyright 2017 Ribose Inc.
2
+ #
3
+
4
+ # URL:
5
+ # https://content.pivotal.io/blog/sanitizing-post-params-with-custom-rack-middleware
6
+ #
7
+ module Rack
8
+ class Cleanser
9
+ class RequestTooLargeException < RuntimeError; end
10
+
11
+ class ParamLengthLimiter
12
+ def initialize(name, options, block)
13
+ @name = name
14
+ @default_max_length = options[:default] || 2048
15
+ @block = block
16
+ end
17
+
18
+ attr_reader :env
19
+
20
+ def filter_exceptions
21
+ env["CONTENT_TYPE"] !~ %r{\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?}n
22
+ end
23
+
24
+ # 2048 is arbitrary
25
+ # In characters.
26
+ def max_length
27
+ result = @block.call(env)
28
+
29
+ if result.is_a? Integer
30
+ result
31
+ else
32
+ @default_max_length
33
+ end
34
+ end
35
+
36
+ def check_val(val)
37
+ case val
38
+ when String then
39
+ if val.length > max_length
40
+ raise RequestTooLargeException, "#{val.length} >= #{max_length}"
41
+ end
42
+ end
43
+ end
44
+
45
+ def scrub!
46
+ rack_input = env["rack.input"].read
47
+ params = Rack::Utils.parse_query(rack_input, "&") if filter_exceptions
48
+
49
+ traverse_hash(params) do |val|
50
+ check_val(val)
51
+ end
52
+ ensure
53
+ env["rack.input"].rewind
54
+ end
55
+
56
+ # Recursively traverse values of given Hash with given block.
57
+ def traverse_hash(hash_or_not, &blk)
58
+ case hash_or_not
59
+ when Hash then
60
+ hash_or_not.each_pair do |_k, v|
61
+ traverse_hash(v, &blk)
62
+ end
63
+ else yield hash_or_not
64
+ end
65
+ end
66
+
67
+ def [](env)
68
+ @env = env
69
+ scrub!
70
+ end
71
+ end
72
+ end
73
+ end