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,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