owasp-esapi-ruby 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/.document +5 -0
  2. data/AUTHORS +5 -0
  3. data/ChangeLog +69 -0
  4. data/ISSUES +0 -0
  5. data/LICENSE +24 -0
  6. data/README +51 -0
  7. data/Rakefile +63 -0
  8. data/VERSION +1 -0
  9. data/lib/codec/base_codec.rb +99 -0
  10. data/lib/codec/css_codec.rb +101 -0
  11. data/lib/codec/encoder.rb +330 -0
  12. data/lib/codec/html_codec.rb +424 -0
  13. data/lib/codec/javascript_codec.rb +119 -0
  14. data/lib/codec/mysql_codec.rb +131 -0
  15. data/lib/codec/oracle_codec.rb +46 -0
  16. data/lib/codec/os_codec.rb +78 -0
  17. data/lib/codec/percent_codec.rb +53 -0
  18. data/lib/codec/pushable_string.rb +114 -0
  19. data/lib/codec/vbscript_codec.rb +64 -0
  20. data/lib/codec/xml_codec.rb +173 -0
  21. data/lib/esapi.rb +68 -0
  22. data/lib/exceptions.rb +37 -0
  23. data/lib/executor.rb +20 -0
  24. data/lib/owasp-esapi-ruby.rb +13 -0
  25. data/lib/sanitizer/xss.rb +59 -0
  26. data/lib/validator/base_rule.rb +90 -0
  27. data/lib/validator/date_rule.rb +92 -0
  28. data/lib/validator/email.rb +29 -0
  29. data/lib/validator/float_rule.rb +76 -0
  30. data/lib/validator/generic_validator.rb +26 -0
  31. data/lib/validator/integer_rule.rb +61 -0
  32. data/lib/validator/string_rule.rb +146 -0
  33. data/lib/validator/validator_error_list.rb +48 -0
  34. data/lib/validator/zipcode.rb +27 -0
  35. data/spec/codec/css_codec_spec.rb +61 -0
  36. data/spec/codec/html_codec_spec.rb +87 -0
  37. data/spec/codec/javascript_codec_spec.rb +45 -0
  38. data/spec/codec/mysql_codec_spec.rb +44 -0
  39. data/spec/codec/oracle_codec_spec.rb +23 -0
  40. data/spec/codec/os_codec_spec.rb +51 -0
  41. data/spec/codec/percent_codec_spec.rb +34 -0
  42. data/spec/codec/vbcript_codec_spec.rb +23 -0
  43. data/spec/codec/xml_codec_spec.rb +83 -0
  44. data/spec/owasp_esapi_encoder_spec.rb +226 -0
  45. data/spec/owasp_esapi_executor_spec.rb +9 -0
  46. data/spec/owasp_esapi_ruby_email_validator_spec.rb +39 -0
  47. data/spec/owasp_esapi_ruby_xss_sanitizer_spec.rb +66 -0
  48. data/spec/owasp_esapi_ruby_zipcode_validator_spec.rb +42 -0
  49. data/spec/spec_helper.rb +10 -0
  50. data/spec/validator/base_rule_spec.rb +29 -0
  51. data/spec/validator/date_rule_spec.rb +40 -0
  52. data/spec/validator/float_rule_spec.rb +31 -0
  53. data/spec/validator/integer_rule_spec.rb +51 -0
  54. data/spec/validator/string_rule_spec.rb +103 -0
  55. data/spec/validator_skeleton.rb +150 -0
  56. metadata +235 -0
@@ -0,0 +1,92 @@
1
+ require 'date'
2
+
3
+ # DateTime now has a to_time method injected in
4
+ class DateTime
5
+ def to_time
6
+ self.offset == 0 ? ::Time.utc(year, month, day, hour, min, sec) : self
7
+ end
8
+ end
9
+
10
+ module Owasp
11
+ module Esapi
12
+ module Validator
13
+
14
+ # A validator performs syntax and possibly semantic validation of a single
15
+ # piece of string data from an untrusted source. This class will return
16
+ # Time objects, as they are more flexible to reformat to for timezones
17
+ # and calendars
18
+ # Format variables, from rdoc
19
+ # %a - The abbreviated weekday name (``Sun'')
20
+ # %A - The full weekday name (``Sunday'')
21
+ # %b - The abbreviated month name (``Jan'')
22
+ # %B - The full month name (``January'')
23
+ # %c - The preferred local date and time representation
24
+ # %d - Day of the month (01..31)
25
+ # %H - Hour of the day, 24-hour clock (00..23)
26
+ # %I - Hour of the day, 12-hour clock (01..12)
27
+ # %j - Day of the year (001..366)
28
+ # %m - Month of the year (01..12)
29
+ # %M - Minute of the hour (00..59)**
30
+ # %p - Meridian indicator (``AM'' or ``PM'')
31
+ # %S - Second of the minute (00..60)
32
+ # %U - Week number of the current year,
33
+ # starting with the first Sunday as the first
34
+ # day of the first week (00..53)
35
+ # %W - Week number of the current year,
36
+ # starting with the first Monday as the first
37
+ # day of the first week (00..53)
38
+ # %w - Day of the week (Sunday is 0, 0..6)
39
+ # %x - Preferred representation for the date alone, no time
40
+ # %X - Preferred representation for the time alone, no date
41
+ # %y - Year without a century (00..99)
42
+ # %Y - Year with century
43
+ # %Z - Time zone name
44
+ # %% - Literal ``%'' character
45
+ class DateRule < BaseRule
46
+ attr :format
47
+ # Create a validator, if no format is specificed
48
+ # We assume %b $d, %Y i.e. September 11, 2001
49
+ def initialize(type, encoder = nil, dateformat = nil)
50
+ super(type,encoder)
51
+ @format = dateformat
52
+ @format = "%B %d, %Y" if dateformat.nil?
53
+ end
54
+
55
+ # Parse the input, raise exceptions if validation fails
56
+ # Returns a Time object
57
+ # see BaseRule
58
+ def valid(context,input)
59
+ # check for empty
60
+ if input.nil? or input.empty?
61
+ if @allow_nil
62
+ return nil
63
+ end
64
+ user = "#{context}: Input date required"
65
+ log = "Input date required: context=#{context}, input=#{input}"
66
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
67
+ end
68
+ # clean the input
69
+ clean = @encoder.canonicalize(input)
70
+ begin
71
+ return DateTime.strptime(clean,@format).to_time
72
+ rescue ArgumentError => failed
73
+ user="#{context}: Input date required"
74
+ log="Input date required: context=#{context}, input=#{input}"
75
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
76
+ end
77
+ end
78
+
79
+ # Calls valid, with any failures causing it to return a zero Time object
80
+ def sanitize(context,input)
81
+ d = Time.new(0)
82
+ begin
83
+ d = valid(context,input)
84
+ rescue ValidationException => e
85
+ end
86
+ return d
87
+ end
88
+
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,29 @@
1
+ require 'validator/generic_validator'
2
+
3
+ module Owasp
4
+ module Esapi
5
+ module Validator
6
+ class Email < GenericValidator
7
+
8
+ EMAIL_REGEX = "^(\\w)+[@](\\w)+[.]\\w{3}$"
9
+ # In order to make a strong validation for email addresses, it might be a good idea to
10
+ # make a check for the domain tld.
11
+ # This is a very optional and beta feature, so it is turned off by default.
12
+ attr_reader :validate_tld
13
+
14
+ def initialize(options=nil)
15
+ validate_tld = false
16
+ @matcher = EMAIL_REGEX
17
+ super(@matcher)
18
+
19
+ unless options.nil?
20
+ if options.has_key? "validate_tld"
21
+ validate_tld = options["validate_tld"]
22
+ end
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,76 @@
1
+ module Owasp
2
+ module Esapi
3
+ module Validator
4
+ class FloatRule < BaseRule
5
+ attr_accessor :min, :max
6
+
7
+ def initialize(type,encoder=nil,min=nil,max=nil)
8
+ super(type,encoder)
9
+ @min = min
10
+ @max = max
11
+ @min = Float::MIN if min.nil?
12
+ @max = Float::MAX if max.nil?
13
+ end
14
+
15
+ # Validate the input context as an integer
16
+ def valid(context,input)
17
+ if input.nil?
18
+ if @allow_nil
19
+ return nil
20
+ end
21
+ puts "::#{input}::"
22
+ user = "#{context}: Input number required"
23
+ log = "Input number required: context=#{context}, input=#{input}"
24
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
25
+ end
26
+ clean = @encoder.canonicalize(input)
27
+ if @min > @max
28
+ user = "#{context}: Invalid number input: context"
29
+ log = "Validation parameter error for number: maxValue ( #{max}) must be greater than minValue ( #{min}) for #{context}"
30
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
31
+ end
32
+ begin
33
+ user = "Invalid number input must be between #{min} and #{max}: context=#{context}"
34
+ log = "Invalid number input must be between #{min} and #{max}: context=#{context}, input=#{input}"
35
+ i = Float(clean)
36
+ #check min
37
+ if i < @min
38
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
39
+ end
40
+ # check max
41
+ if i > @max
42
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
43
+ end
44
+ # check infinity
45
+ if i.infinite?
46
+ user = "#{context}: Invalid number input: context"
47
+ log = "Invalid double input is infinite context=#{context} input=#{input}"
48
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
49
+ end
50
+ # checknan
51
+ if i.nan?
52
+ user = "#{context}: Invalid number input: context"
53
+ log = "Invalid double input not a number context=#{context} input=#{input}"
54
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
55
+ end
56
+ return i
57
+ rescue Exception => e
58
+ user = "#{context}: Input number required"
59
+ log = "Input number required: context=#{context}, input=#{input}"
60
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
61
+ end
62
+ end
63
+
64
+ # This will call valid and return a 0 if its invalid
65
+ def sanitize(context,input)
66
+ result = 0
67
+ begin
68
+ result= valid(context,input)
69
+ rescue ValidationException => e
70
+ end
71
+ result
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,26 @@
1
+ # This is the generic validator class that it will be the dad of all specific validation classes.
2
+ module Owasp
3
+ module Esapi
4
+ module Validator
5
+ class GenericValidator
6
+
7
+ attr_accessor :matcher
8
+
9
+ # Creates a new generic validator.
10
+ # @param [String] matcher the regular expression to be matched from this validator
11
+ def initialize(matcher)
12
+ @matcher = matcher
13
+ end
14
+
15
+ # Validate a string against the matcher
16
+ # @param [String] string the string that need to be validated
17
+ # @return [Boolean] true if the string matches the regular expression, false otherwise
18
+ def valid?(string)
19
+ r = Regexp.new(@matcher)
20
+
21
+ !(string =~ r).nil?
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,61 @@
1
+ module Owasp
2
+ module Esapi
3
+ module Validator
4
+ class IntegerRule < BaseRule
5
+ attr_accessor :min, :max
6
+
7
+ def initialize(type,encoder=nil,min=nil,max=nil)
8
+ super(type,encoder)
9
+ @min = min
10
+ @max = max
11
+ @min = Integer::MIN if min.nil?
12
+ @max = Integer::MAX if max.nil?
13
+ end
14
+
15
+ # Validate the input context as an integer
16
+ def valid(context,input)
17
+ if input.nil?
18
+ if @allow_nil
19
+ return nil
20
+ end
21
+ user = "#{context}: Input number required"
22
+ log = "Input number required: context=#{context}, input=#{input}"
23
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
24
+ end
25
+ clean = @encoder.canonicalize(input)
26
+ if @min > @max
27
+ user = "#{context}: Invalid number input: context"
28
+ log = "Validation parameter error for number: maxValue ( #{max}) must be greater than minValue ( #{min}) for #{context}"
29
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
30
+ end
31
+ begin
32
+ user = "Invalid number input must be between #{min} and #{max}: context=#{context}"
33
+ log = "Invalid number input must be between #{min} and #{max}: context=#{context}, input=#{input}"
34
+ i = Integer(clean)
35
+ if i < @min
36
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
37
+ end
38
+ if i > @max
39
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
40
+ end
41
+ return i
42
+ rescue Exception => e
43
+ user = "#{context}: Input number required"
44
+ log = "Input number required: context=#{context}, input=#{input}"
45
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
46
+ end
47
+ end
48
+
49
+ # SThis will call valid and return a 0 if its invalid
50
+ def sanitize(context,input)
51
+ result = 0
52
+ begin
53
+ result= valid(context,input)
54
+ rescue ValidationException => e
55
+ end
56
+ result
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,146 @@
1
+ require 'stringio'
2
+
3
+ module Owasp
4
+ module Esapi
5
+ module Validator
6
+
7
+ # A validator performs syntax and possibly semantic validation of a single
8
+ # piece of string data from an untrusted source.
9
+ class StringRule < BaseRule
10
+ attr_writer :min,:max,:canonicalize
11
+
12
+ # Create an instance of the String vlidator
13
+ # whitelist_pattern is an optionla white listing regex
14
+ def initialize(type,encoder = nil,whitelist_pattern = nil)
15
+ super(type,encoder)
16
+ @white_list = []
17
+ @black_list = []
18
+ @white_list << whitelist_pattern unless whitelist_pattern.nil?
19
+ @min = 0
20
+ @max = 0
21
+ @canonicalize = false
22
+ end
23
+
24
+ # Add a whitelist regex
25
+ def add_whitelist(p)
26
+ raise ArgumentError.new("Nil Pattern") if p.nil?
27
+ @white_list << create_regex(p)
28
+ end
29
+
30
+ # Add a blacklist regex
31
+ def add_blacklist(p)
32
+ raise ArgumentError.new("Nil Pattern") if p.nil?
33
+ @black_list << create_regex(p)
34
+ end
35
+
36
+ # Ensure we dont show the warnings to stderr, just fail the regexp
37
+ def create_regex(p) #:nodoc:
38
+ output = StringIO.open('','w')
39
+ $stderr = output
40
+ begin
41
+ r = /#{p}/
42
+ ensure
43
+ output.close
44
+ $stderr = STDERR
45
+ end
46
+ end
47
+
48
+ # Checks input against whitelists.
49
+ def check_white_list(context,input,original = nil)
50
+ original = input.dup if original.nil?
51
+ @white_list.each do |p|
52
+ match = p.match(input)
53
+ if match.nil? or not match[0].eql?(input)
54
+ # format user msg
55
+ user = "#{context}: Invalid input. Conform to #{p.to_s}"
56
+ user << " with a max length of #{@max}" unless @max == 0
57
+ # format log message
58
+ log = "Invalid input: context=#{context}, type=#{@name}, pattern=#{p.to_s}"
59
+ log << ", input=#{input}, original=#{original}"
60
+ # raise an error
61
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
62
+ end
63
+ end
64
+ input
65
+ end
66
+
67
+ # Checks input against blacklists.
68
+ def check_black_list(context,input,original = nil)
69
+ original = input.dup if original.nil?
70
+ @black_list.each do |p|
71
+ if p.match(input)
72
+ # format user msg
73
+ user = "#{context}: Invalid input. Dangerous input matching #{p.to_s}"
74
+ # format log message
75
+ log = "Dangerous input: context=#{context}, type=#{@name}, pattern=#{p.to_s}"
76
+ log << ", input=#{input}, original=#{original}"
77
+ # raise an error
78
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
79
+ end
80
+ end
81
+ input
82
+ end
83
+
84
+ # Checks input lengths
85
+ def check_length(context,input,original = nil)
86
+ original = input.dup if original.nil?
87
+ # check min value
88
+ if input.size < @min
89
+ user = "#{context}: Invalid input, The min length is #{@min} characters"
90
+ log = "Input didnt meet #{@min} chars by #{input.size}: context=#{context}, type=#{@name}, pattern=#{p.to_s}"
91
+ log << ", input=#{input}, original=#{original}"
92
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
93
+ end
94
+ # check max value
95
+ if input.size > @max and @max > 0
96
+ user = "#{context}: Invalid input, The max length is #{@max} characters"
97
+ log = "Input exceed #{@max} chars by #{input.size}: context=#{context}, type=#{@name}, pattern=#{p.to_s}"
98
+ log << ", input=#{input}, original=#{original}"
99
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
100
+ end
101
+ input
102
+ end
103
+
104
+ def check_empty(context,input,orig = nil)
105
+ return nil if @allow_nil and input.nil?
106
+ unless input.nil?
107
+ original = input.dup if original.nil?
108
+ return input unless input.empty?
109
+ end
110
+ user = "#{context}: Input required."
111
+ log = "Input required: context=#{context}, type=#{@name}, pattern=#{p.to_s}"
112
+ log << ", input=#{input}, original=#{original}"
113
+ raise Owasp::Esapi::ValidationException.new(user,log,context)
114
+ end
115
+
116
+ # Remvoe any non alpha numerics form the string
117
+ def sanitize(context,input)
118
+ whitelist(input,Owasp::Esapi::Ecnoder::CHAR_ALPHANUMERIC)
119
+ end
120
+
121
+ # Parse the input, raise exceptions if validation fails
122
+ # see BaseRule
123
+ def valid(context,input)
124
+
125
+ data = nil
126
+ return nil if check_empty(context,input).nil?
127
+ # check for pre-canonicalize if we are in sanitize mode
128
+ check_length(context,input) if @canonicalize
129
+ check_white_list(context,input) if @canonicalize
130
+ check_black_list(context,input) if @canonicalize
131
+ if @canonicalize
132
+ data = encoder.canonicalize(input)
133
+ else
134
+ data = input
135
+ end
136
+ # no check again after we figured otu canonicalization
137
+ return nil if check_empty(context,input).nil?
138
+ check_length(context,input)
139
+ check_white_list(context,input)
140
+ check_black_list(context,input)
141
+ data
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,48 @@
1
+ module Owasp
2
+ module Esapi
3
+ module Validator
4
+ # List of Validation exceptions
5
+ # this list is indexed by the context
6
+ class ValidatorErrorList
7
+
8
+ # Create a new list
9
+ def initialize()
10
+ @errors = {}
11
+ end
12
+
13
+ # Add an error to the list. We will raise ArgumentException if any of the following is true:
14
+ # 1. error is nil
15
+ # 2. context is nil
16
+ # 3. we already have an error for the given context
17
+ # 4. the error isnt a ValidationException
18
+ def <<(error)
19
+ raise ArgumentError.new("Invalid Error") if error.nil?
20
+ if error.instance_of?(ValidationException)
21
+ context = error.context
22
+ raise ArgumentError.new("Invalid context") if context.nil?
23
+ raise ArgumentError.new("Duplicate error") if @errors.has_key?(context)
24
+ @errors[context] = error
25
+ else
26
+ raise ArgumentError.new("Exception was not a ValdiaitonException")
27
+ end
28
+ end
29
+
30
+ # Return true if this list is empty
31
+ def empty?
32
+ @errors.empty?
33
+ end
34
+
35
+ # Return the size of the list
36
+ def size
37
+ @errors.size
38
+ end
39
+
40
+ # Return the array of errors in this list
41
+ def errors
42
+ @errors.values
43
+ end
44
+
45
+ end
46
+ end
47
+ end
48
+ end