owasp-esapi-ruby 0.30.0

Sign up to get free protection for your applications and to get access to all the features.
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