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,131 @@
1
+ #
2
+ # Codec to provide for MySQL string support
3
+ # http://mirror.yandex.ru/mirrors/ftp.mysql.com/doc/refman/5.0/en/string-syntax.html for details
4
+ module Owasp
5
+ module Esapi
6
+ module Codec
7
+ class MySQLCodec < BaseCodec
8
+ MYSQL_MODE = 0 # MySQL standard mode
9
+ ANSI_MODE = 1; # ANSI escape mode
10
+
11
+ # create a mysql codec.
12
+ # mode must be either MYSQL_MODE or ANSI_MODE
13
+ # The mode sets wether to use ansi mode in mysql or not
14
+ # defaults to MYSQL_MODE
15
+ def initialize(mode = 0)
16
+ if mode < MYSQL_MODE or mode > ANSI_MODE
17
+ raise RangeError.new()
18
+ end
19
+ @mode = mode
20
+ end
21
+
22
+ # Returns quote-encoded *character*
23
+ def encode_char(immune,input)
24
+ return input if immune.include?(input)
25
+ hex = hex(input)
26
+ return input if hex.nil?
27
+ return to_ansi(input) if @mode == ANSI_MODE
28
+ return to_mysql(input) if @mode == MYSQL_MODE
29
+ end
30
+
31
+ # Returns the decoded version of the character starting at index, or
32
+ # nil if no decoding is possible.
33
+ #
34
+ # Formats all are legal (case sensitive)
35
+ # In ANSI_MODE '' decodes to '
36
+ # In MYSQL_MODE \x decodes to x (or a small list of specials)
37
+ def decode_char(input)
38
+ return from_ansi(input) if @mode == ANSI_MODE
39
+ return from_mysql(input) if @mode == MYSQL_MODE
40
+ end
41
+
42
+ # encode ' only
43
+ def to_ansi(input) #:nodoc:
44
+ return "\'\'" if input == "\'"
45
+ input
46
+ end
47
+
48
+ # encode for NO_BACKLASH_MODE
49
+ def to_mysql(input) # :nodoc:
50
+ c = input.ord
51
+ return "\\0" if c == 0x00
52
+ return "\\b" if c == 0x08
53
+ return "\\t" if c == 0x09
54
+ return "\\n" if c == 0x0a
55
+ return "\\r" if c == 0x0d
56
+ return "\\Z" if c == 0x1a
57
+ return "\\\"" if c == 0x22
58
+ return "\\%" if c == 0x25
59
+ return "\\'" if c == 0x27
60
+ return "\\\\" if c == 0x5c
61
+ return "\\_" if c == 0x5f
62
+ "\\#{input}"
63
+ end
64
+
65
+ # decode a char with ansi only compliane i.e. apostrohpe only
66
+ def from_ansi(input) # :nodoc:
67
+ input.mark
68
+ first = input.next
69
+
70
+ # check first char
71
+ if first.nil?
72
+ input.reset
73
+ return nil
74
+ end
75
+
76
+ unless first == "\'"
77
+ input.reset
78
+ return nil
79
+ end
80
+
81
+ # check second char
82
+ second = input.next
83
+ if second.nil?
84
+ input.reset
85
+ return nil
86
+ end
87
+
88
+ # if second isnt an encoded char return nil
89
+ unless second == "\'"
90
+ input.reset
91
+ return nil
92
+ end
93
+ "\'"
94
+ end
95
+
96
+ # decode a char using mysql NO_BACKSLAH_QUOTE rules
97
+ def from_mysql(input) # :nodoc:
98
+ input.mark
99
+ # check first
100
+ first = input.next
101
+ if first.nil?
102
+ input.reset
103
+ return nil
104
+ end
105
+
106
+ # check second
107
+ second = input.next
108
+ if second.nil?
109
+ input.reset
110
+ return nil
111
+ end
112
+
113
+ return 0x00.chr if second == "0"
114
+ return 0x08.chr if second == "b"
115
+ return 0x08.chr if second == "t"
116
+ return 0x0a.chr if second == "n"
117
+ return 0x0d.chr if second == "r"
118
+ return 0x1a.chr if second == "z"
119
+ return 0x22.chr if second == "\""
120
+ return 0x25.chr if second == "%"
121
+ return 0x27.chr if second == "\'"
122
+ return 0x5c.chr if second == "\\"
123
+ return 0x5f.chr if second == "_"
124
+ # not an escape
125
+ second
126
+ end
127
+
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,46 @@
1
+ #
2
+ # Codec to provide for Oracle string support
3
+ # see http://oraqa.com/2006/03/20/how-to-escape-single-quotes-in-strings for details
4
+ # This will only prevent SQLinjection in the case of user data being placed within an
5
+ # Oracle quoted string such as select * from table where field = ' USERDATA '
6
+ module Owasp
7
+ module Esapi
8
+ module Codec
9
+ class OracleCodec < BaseCodec
10
+
11
+ # Encodes ' to ''
12
+ def encode_char(immune,input)
13
+ return "\'\'" if input == "\'"
14
+ input
15
+ end
16
+
17
+ # Returns the decoded version of the character starting at index, or
18
+ # nil if no decoding is possible.
19
+ #
20
+ # Formats all are legal
21
+ # '' decodes to '
22
+ def decode_char(input)
23
+ # check first *char*
24
+ input.mark
25
+ first = input.next
26
+ if first.nil?
27
+ input.reset
28
+ return nil
29
+ end
30
+ # if it isnt an encoded string return nil
31
+ unless first == "\'"
32
+ input.reset
33
+ return nil
34
+ end
35
+ # if second isnt an encoded marker return nil
36
+ second = input.next
37
+ unless second == "\'"
38
+ input.reset
39
+ return nil
40
+ end
41
+ return "\'"
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,78 @@
1
+ require 'rbconfig'
2
+
3
+ # Operating system codec for escape characters for HOST commands
4
+ # We look at Unix style (max, linux) and Windows style
5
+ module Owasp
6
+ module Esapi
7
+ module Codec
8
+ class OsCodec < BaseCodec
9
+ # Window Host flag
10
+ WINDOWS_HOST = :Windows
11
+ # Unix Host flag
12
+ UNIX_HOST = :Unix
13
+
14
+ # Setup the code, if no os is passed in the codec
15
+ # will guess the OS based on the ruby host_os variable
16
+ def initialize(os = nil)
17
+ @host = nil
18
+ @escape_char = ''
19
+ host_os = os
20
+ if os.nil?
21
+ host_os = case Config::CONFIG['host_os']
22
+ when /mswin|windows/i then WINDOWS_HOST
23
+ when /linux/i then UNIX_HOST
24
+ when /darwin/i then UNIX_HOST
25
+ when /sunos|solaris/i then UNIX_HOST
26
+ else UNIX_HOST
27
+ end
28
+ end
29
+ if host_os == WINDOWS_HOST
30
+ @host = WINDOWS_HOST
31
+ @escape_char = '^'
32
+ elsif host_os == UNIX_HOST
33
+ @host = UNIX_HOST
34
+ @escape_char = '\\'
35
+ end
36
+ end
37
+
38
+ # get the configured OS
39
+ def os
40
+ @host
41
+ end
42
+
43
+ # Returns shell encoded character
44
+ # ^ - for windows
45
+ # \\ - for unix
46
+ def encode_char(immune,input)
47
+ return input if immune.include?(input)
48
+ return input if hex(input).nil?
49
+ return "#{@escape_char}#{input}"
50
+ end
51
+
52
+ # Returns the decoded version of the character starting at index, or
53
+ # nil if no decoding is possible.
54
+ # <p>
55
+ # Formats all are legal both upper/lower case:
56
+ # ^x - all special characters when configured for WINDOWS
57
+ # \\ - all special characters when configured for UNIX
58
+ def decode_char(input)
59
+ input.mark
60
+ first = input.next
61
+ # check first char
62
+ if first.nil?
63
+ input.reset
64
+ return nil
65
+ end
66
+ # if it isnt escape return nil
67
+ if first != @escape_char
68
+ input.reset
69
+ return nil
70
+ end
71
+ # get teh escape value
72
+ return input.next
73
+ end
74
+
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,53 @@
1
+ # Implementation of the Codec interface for percent encoding (aka URL encoding).
2
+ module Owasp
3
+ module Esapi
4
+ module Codec
5
+ class PercentCodec < BaseCodec
6
+
7
+ # Encode a character for URLs
8
+ def encode_char(immune,input)
9
+ return input if input =~ /[a-zA-Z0-9_.-]/
10
+ # RFC compliance
11
+ return "+" if input == " "
12
+ val = ''
13
+ input.each_byte do |b|
14
+ val << '%' << b.ord.to_h.upcase
15
+ end
16
+ val
17
+ end
18
+
19
+ # Formats all are legal both upper/lower case:
20
+ # %hh;
21
+ def decode_char(input)
22
+ input.mark
23
+ first = input.next
24
+ if first.nil?
25
+ input.reset
26
+ return nil
27
+ end
28
+ # check if this is an encoded character
29
+ if first != '%'
30
+ input.reset
31
+ return nil
32
+ end
33
+ # search for 2 hex digits
34
+ tmp = ''
35
+ for i in 0..1 do
36
+ c = input.next_hex
37
+ tmp << c unless c.nil?
38
+ end
39
+ # we found 2, convert to a number
40
+ if tmp.size == 2
41
+ i = tmp.hex
42
+ begin
43
+ return i.chr(Encoding::UTF_8) if i >= START_CODE_POINT and i <= END_CODE_POINT
44
+ rescue Exception => e
45
+ end
46
+ end
47
+ input.reset
48
+ nil
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,114 @@
1
+ # The pushback string is used by Codecs to allow them to push decoded characters back onto a string
2
+ # for further decoding. This is necessary to detect double-encoding.
3
+
4
+ module Owasp
5
+ module Esapi
6
+ module Codec
7
+ class PushableString
8
+ attr :index
9
+
10
+ #
11
+ # Setup a pushable string
12
+ # stream will setup UTF_8 encoding on the input
13
+ def initialize(string)
14
+ @input = string.force_encoding(Encoding::UTF_8)
15
+ @index = 0
16
+ @mark = 0
17
+ @temp = nil
18
+ @push = nil
19
+ end
20
+
21
+ # Get the next token off of the stream
22
+ def next
23
+ unless @push.nil?
24
+ t = @push
25
+ @push = nil
26
+ return t
27
+ end
28
+ return nil if @input.nil?
29
+ return nil if @input.size == 0
30
+ return nil if @index >= @input.size
31
+
32
+ t = @input[@index]
33
+ @index += 1
34
+ t
35
+ end
36
+
37
+ # fetch the next hex token in the string or nil
38
+ def next_hex
39
+ c = self.next
40
+ return nil if c.nil?
41
+ return c if hex?(c)
42
+ nil
43
+ end
44
+
45
+ # Fetch the next octal token int eh string or nil
46
+ def next_octal
47
+ c = self.next
48
+ return nil if c.nil?
49
+ return c if octal?(c)
50
+ nil
51
+ end
52
+
53
+ # Check to see if we have another token on the stream
54
+ def next?
55
+ !@push.nil? ? true : @input.nil? ? false : @input.empty? ? false : @index >= @input.length ? false : true
56
+ end
57
+
58
+ # Push a character back onto the string, this is a unread operation
59
+ def push(c)
60
+ @push = c
61
+ end
62
+
63
+ # Peek into teh stream and see if the next character is the one in question
64
+ def peek?(c)
65
+ return true if !@push.nil? and @push == c
66
+ return false if @input.empty?
67
+ return false if @input.nil?
68
+ return false if @index >= @input.size
69
+ @input[@index] == c
70
+ end
71
+
72
+ # Peek into the stream and fetch teh next character without moving the index
73
+ def peek
74
+ return @push if !@push.nil?
75
+ return nil if @input.nil?
76
+ return nil if @input.empty?
77
+ return nil if @index >= @input.size
78
+ @input[@index]
79
+ end
80
+
81
+ # Mark the stream for rewind
82
+ def mark
83
+ @temp = @push
84
+ @mark = @index
85
+ end
86
+
87
+ # Check if a given character is a hexadecimal character
88
+ def hex?(c)
89
+ return false if c.nil?
90
+ c =~ /[a-fA-F0-9]/
91
+ end
92
+
93
+ # Check if a given character is an octal character
94
+ def octal?(c)
95
+ return false if c.nil?
96
+ c =~ /[0-7]/
97
+ end
98
+
99
+ # Reset the index back to the mark
100
+ def reset
101
+ @push = @temp
102
+ @index = @mark
103
+ end
104
+
105
+ # Fetch the rest of the string from the current index
106
+ def remainder
107
+ t = @input.slice(@index,@input.size-@index)
108
+ return @push + t unless @push.nil?
109
+ t
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,64 @@
1
+ # Implementation of the Codec interface for 'quote' encoding from VBScript.
2
+ module Owasp
3
+ module Esapi
4
+ module Codec
5
+ class VbScriptCodec < BaseCodec
6
+
7
+ # Encode a String so that it can be safely used in a specific context.
8
+ def encode(immune, input)
9
+ encoded_string = ''
10
+ encoding = false
11
+ inquotes = false
12
+ encoded_string.encode!(Encoding::UTF_8)
13
+ i = 0
14
+ input.encode(Encoding::UTF_8).chars do |c|
15
+ if Owasp::Esapi::Encoder::CHAR_ALPHANUMERIC.include?(c) or immune.include?(c)
16
+ encoded_string << "&" if encoding and i > 0
17
+ encoded_string << "\"" if !inquotes and i > 0
18
+ encoded_string << c
19
+ inquotes = true
20
+ encoding = false
21
+ else
22
+ encoded_string << "\"" if inquotes and i < input.size
23
+ encoded_string << "&" if i > 0
24
+ encoded_string << encode_char(immune,c)
25
+ inquotes = false
26
+ encoding = true
27
+ end
28
+ i += 1
29
+ end
30
+ encoded_string
31
+ end
32
+ # Returns quote-encoded character
33
+ def encode_char(immune,input)
34
+ return input if immune.include?(input)
35
+ hex = hex(input)
36
+ return input if hex.nil?
37
+ return "chrw(#{input.ord})"
38
+ end
39
+
40
+ # Returns the decoded version of the character starting at index, or
41
+ # nil if no decoding is possible.
42
+ #
43
+ # Formats all are legal both upper/lower case:
44
+ # "x - all special characters
45
+ # " + chr(x) + " - not supported
46
+
47
+ def decode_char(input)
48
+ input.mark();
49
+ first = input.next
50
+ if first.nil?
51
+ input.reset
52
+ return nil;
53
+ end
54
+ # if this is not an encoded character, return null
55
+ if first != "\""
56
+ input.reset
57
+ return nil
58
+ end
59
+ input.next
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end