Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added os and javascript codecs. Added in spec file for thos codecs an…

…d updated encoder spec. TODO: add in some convience methods for encode_for_os and encode_for_js. Refactored some things inside pushable string to be more ruby like in method names. Will keep going over code and refactoing as time permits. Still need a vbscript, oracle, and mysql codecs
  • Loading branch information...
commit 1d14f2d43ac4e73ed036a4d5f3875cfb3ede4b84 1 parent 6da21e5
@washu washu authored
View
2  lib/codec/base_codec.rb
@@ -52,7 +52,7 @@ def encode_char(immune, input)
=begin
helper method for codecs to get the hex value of a character
=end
- def hex_value(c)
+ def hex(c)
return nil if c.nil?
b = c[0].ord
if b < 0xff
View
6 lib/codec/css_codec.rb
@@ -17,7 +17,7 @@ def encode_char(immune, input)
# check immune
return input if immune.include?(input)
# check for alpha numeric
- hex = hex_value(input)
+ hex = hex(input)
# add a space at end to terminate under css
return "\\#{hex} " unless hex.nil? or hex.empty?
return input
@@ -86,7 +86,7 @@ def decode_char(input)
# handle the skip ahead. Ruby case doesnt allow for fall through so we inlined the small setup
return decode_char(input) if second == "\n" || second == "\f" || second == "\u0000" || fallthrough
# non hex test
- return second if !input.is_hex(second)
+ return second if !input.hex?(second)
# check for 6 hex digits for rule 3
tmp = second
for i in 1..5 do
@@ -94,7 +94,7 @@ def decode_char(input)
if c.nil? or c =~ /\s/
break
end
- if input.is_hex(c)
+ if input.hex?(c)
tmp << c
else
input.push(c)
View
48 lib/codec/encoder.rb
@@ -12,25 +12,34 @@ class Encoder
IMMUNE_OS = [ '-' ]
IMMUNE_XMLATTR = [ ',', '.', '-', '_' ]
IMMUNE_XPATH = [ ',', '.', '-', '_', ' ' ]
- @@codecs = []
- @@html_codec = Owasp::Esapi::Codec::HtmlCodec.new
- @@xml_codec = nil
- @@percent_codec = Owasp::Esapi::Codec::PercentCodec.new
- @@js_codec = nil
- @@vb_codec = nil
- @@css_codec = Owasp::Esapi::Codec::CssCodec.new
+ PASSWORD_SPECIALS = "!$*-.=?@_"
+ CHAR_LCASE = "abcdefghijklmnopqrstuvwxyz"
+ CHAR_UCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ CHAR_DIGITS = "0123456789"
+ CHAR_SPECIALS = "!$*+-.=?@^_|~"
+ CHAR_LETTERS = "#{CHAR_LCASE}#{CHAR_UCASE}"
+ CHAR_ALPHANUMERIC = "#{CHAR_LETTERS}#{CHAR_DIGITS}"
# Create an encoder, optionally pass in a list of codecs to use
def initialize(configured_codecs = nil)
+ # codec list
+ @codecs = []
+ # default codecs
+ @html_codec = Owasp::Esapi::Codec::HtmlCodec.new
+ @percent_codec = Owasp::Esapi::Codec::PercentCodec.new
+ @js_codec = Owasp::Esapi::Codec::JavascriptCodec.new
+ @vb_codec = nil
+ @css_codec = Owasp::Esapi::Codec::CssCodec.new
unless configured_codecs.nil?
- configured_codes.each do |codec|
- @@codecs << codec
+ configured_codecs.each do |c|
+ @codecs << c
end
else
# setup some defaults codecs
- @@codecs << @@css_codec
- @@codecs << @@html_codec
- @@codecs << @@percent_codec
+ puts "Setting up Default Codecs"
+ @codecs << @html_codec
+ @codecs << @percent_codec
+ @codecs << @js_codec
end
end
=begin
@@ -61,7 +70,7 @@ def sanitize(input, strict)
clean = false
while !clean
clean = true
- @@codecs.each do |codec|
+ @codecs.each do |codec|
old = working
working = codec.decode(working)
if !old.eql?(working)
@@ -106,20 +115,25 @@ def sanitize(input, strict)
=end
def encode_for_css(input)
return nil if input.nil?
- @@css_codec.encode(IMMUNE_CSS,input)
+ @css_codec.encode(IMMUNE_CSS,input)
+ end
+
+ def encode_for_javascript(input)
+ return nil if input.nil?
+ @js_codec.encode(IMMUNE_JAVASCRIPT,input)
end
def encode_for_html(input)
return nil if input.nil?
- @@html_codec.encode(IMMUNE_HTML,input)
+ @html_codec.encode(IMMUNE_HTML,input)
end
def dencode_for_html(input)
return nil if input.nil?
- @@html_codec.decode(input)
+ @html_codec.decode(input)
end
def encode_for_html_attr(input)
return nil if input.nil?
- @@html_codec.encode(IMMUNE_HTMLATTR,input)
+ @html_codec.encode(IMMUNE_HTMLATTR,input)
end
end
View
2  lib/codec/html_codec.rb
@@ -19,7 +19,7 @@ def encode_char(immune, input)
c = input
return input if immune.include?(input)
# check for alpha numeric
- hex = hex_value(input)
+ hex = hex(input)
return input if hex.nil?
# check to see if we need to replace an entity
if ( c.ord <= 0x1f and c != '\t' and c != '\n' and c != '\r' ) || ( c.ord >= 0x7f and c.ord <= 0x9f )
View
109 lib/codec/javascript_codec.rb
@@ -0,0 +1,109 @@
+module Owasp
+ module Esapi
+ module Codec
+ class JavascriptCodec < BaseCodec
+
+ def encode_char(immune,input)
+ return input if immune.include?(input)
+ return input if hex(input).nil?
+
+ temp = hex(input)
+ if temp.hex < 256
+ return "\\x#{'00'[temp.size,2-temp.size]}#{temp.upcase}"
+ end
+ return "\\u#{'0000'[temp.size,4-temp.size]}#{temp.upcase}"
+
+ end
+
+ def decode_char(input)
+
+ input.mark
+ first = input.next
+ if first.nil?
+ input.reset
+ return nil
+ end
+ # check to see if we are dealing with an encoded char
+ if first!= "\\"
+ input.reset
+ return nil
+ end
+ second = input.next
+ if second.nil?
+ input.reset
+ return nil
+ end
+
+ #Check octal codes
+ return 0x08.chr if second == "b"
+ return 0x09.chr if second == "t"
+ return 0x0a.chr if second == "n"
+ return 0x0b.chr if second == "v"
+ return 0x0c.chr if second == "f"
+ return 0x0d.chr if second == "r"
+ return 0x22.chr if second == "\""
+ return 0x27.chr if second == "\'"
+ return 0x5c.chr if second == "\\"
+ if second.downcase == "x" # Hex encoded value
+ temp = ''
+ for i in 0..1 do
+ c = input.next_hex
+ temp << c unless c.nil?
+ if c.nil?
+ input.reset
+ return nil
+ end
+ end
+ i = temp.hex
+ begin
+ return i.chr(Encoding::UTF_8) if i >= START_CODE_POINT and i <= END_CODE_POINT
+ rescue Exception => e
+ input.reset
+ return nil
+ end
+ elsif second.downcase == "u" # Unicode encoded value
+ temp = ''
+ for i in 0..3 do
+ c = input.next_hex
+ temp << c unless c.nil?
+ if c.nil?
+ input.reset
+ return nil
+ end
+ end
+ i = temp.hex
+ begin
+ return i.chr(Encoding::UTF_8) if i >= START_CODE_POINT and i <= END_CODE_POINT
+ rescue Exception => e
+ input.reset
+ return nil
+ end
+ elsif input.octal?(second) # Octal encoded value
+ temp = second
+ c = input.next
+ unless input.octal?(c)
+ input.push(c)
+ else
+ temp << c
+ c = input.next
+ unless input.octal?(c)
+ input.push(c)
+ else
+ temp << c
+ end
+ end
+ # build a number
+ i = temp.to_i(8)
+ begin
+ return i.chr(Encoding::UTF_8) if i >= START_CODE_POINT and i <= END_CODE_POINT
+ rescue Exception => e
+ input.reset
+ return nil
+ end
+ end
+ return second
+ end
+ end
+ end
+ end
+end
View
73 lib/codec/os_codec.rb
@@ -0,0 +1,73 @@
+class OSDetect
+
+ def self.os
+
+ end
+end
+require 'rbconfig'
+=begin
+ Operating system codec for escape characters for HOST commands
+ We look at Unix style (max, linux) and Windows style
+=end
+module Owasp
+ module Esapi
+ module Codec
+ class OsCodec < BaseCodec
+ WINDOWS_HOST = :Windows
+ UNIX_HOST = :Unix
+ def initialize(os = nil)
+ @host = nil
+ @escape_char = ''
+ host_os = os
+ if os.nil?
+ host_os = case Config::CONFIG['host_os']
+ when /mswin|windows/i then WINDOWS_HOST
+ when /linux/i then UNIX_HOST
+ when /darwin/i then UNIX_HOST
+ when /sunos|solaris/i then UNIX_HOST
+ else UNIX_HOST
+ end
+ end
+ if host_os == WINDOWS_HOST
+ @host = WINDOWS_HOST
+ @escape_char = '^'
+ elsif host_os == UNIX_HOST
+ @host = UNIX_HOST
+ @escape_char = '\\'
+ end
+ end
+
+=begin
+ get the host OS type
+=end
+ def os
+ @host
+ end
+
+ def encode_char(immune,input)
+ return input if immune.include?(input)
+ return input if hex(input).nil?
+ return "#{@escape_char}#{input}"
+ end
+
+ def decode_char(input)
+ input.mark
+ first = input.next
+ # check first char
+ if first.nil?
+ input.reset
+ return nil
+ end
+ # if it isnt escape return nil
+ if first != @escape_char
+ input.reset
+ return nil
+ end
+ # get teh escape value
+ return input.next
+ end
+
+ end
+ end
+ end
+end
View
2  lib/codec/percent_codec.rb
@@ -1,5 +1,5 @@
#
-# Originally I was using teh cgi lib to encode and decode values
+# Originally I was using the cgi lib to encode and decode values
# however i changed that approach for more control
#
module Owasp
View
8 lib/codec/pushable_string.rb
@@ -41,7 +41,7 @@ def next
def next_hex
c = self.next
return nil if c.nil?
- return c if is_hex(c)
+ return c if hex?(c)
return nil
end
=begin
@@ -50,7 +50,7 @@ def next_hex
def next_octal
c = self.next
return nil if c.nil?
- return c if is_octal(c)
+ return c if octal?(c)
return nil
end
=begin
@@ -96,7 +96,7 @@ def mark
check if a given character is a hexadecimal character
meaning a through f and 0 through 9
=end
- def is_hex(c)
+ def hex?(c)
return false if c.nil?
c =~ /[a-fA-F0-9]/
end
@@ -104,7 +104,7 @@ def is_hex(c)
check if a given character is an octal character
means 0 through 7
=end
- def is_octal(c)
+ def octal?(c)
return false if c.nil?
c =~ /[0-7]/
end
View
39 lib/esapi.rb
@@ -1,11 +1,30 @@
-# STUB code, this should be replaced by config file loading/initializtion
#
-module Owasp
+# Class loading mechanism, we use this to create new instances of objects based
+# on config data. This allows a user to set their own config for instance to use thier
+# own implmentation of a given class. ClassLoader based on Rails constantize
+#
+class ClassLoader
+ def self.load_class(class_name)
+ # we are using ruby 1.9.2 as a requirement, so we can use the inheritance
+ # of const_get to find our object. if mis-spelled it will raise a NameError
+ names = class_name.split("::")
+ klass = Object
+ names.each do |name|
+ klass = klass.const_get(name)
+ end
+ klass.new
+ end
+end
+module Owasp
class Configuration
+ attr_accessor :logger, :encoder
def ids?
return true
end
+ def get_encoder_class
+
+ end
end
class Logger
@@ -16,12 +35,28 @@ def warn(msg)
module Esapi
+ # seutp ESAPI
+ def self.setup
+ @config ||= Configuration.new
+ yield @config if block_given?
+ process_config(@config)
+ end
+
+
def self.security_config
@security ||= Configuration.new
end
def self.logger
@logger ||= Logger.new
end
+ def self.encoder
+ @encoder ||= ClassLoader.load_class("Owasp::Esapi::Encoder")
+ end
+
+ private
+ # Process the config data to setup esapi
+ def self.process_config(conf)
+ end
end
end
View
2  lib/owasp-esapi-ruby.rb
@@ -9,4 +9,6 @@
require 'codec/css_codec'
require 'codec/html_codec'
require 'codec/percent_codec'
+require 'codec/javascript_codec'
+require 'codec/os_codec'
require 'codec/encoder'
View
4 spec/owasp_esapi_css_codec_spec.rb
@@ -51,6 +51,10 @@ module Codec
m.should == "abcxyz"
end
+ it "should decode \\3c as <" do
+ codec.decode("\\3c").should == "<"
+ end
+
end
end
end
View
42 spec/owasp_esapi_encoder_spec.rb
@@ -3,7 +3,7 @@
module Owasp
module Esapi
describe Encoder do
- let (:encoder) { Owasp::Esapi::Encoder.new }
+ let (:encoder) { Owasp::Esapi.encoder }
# Sanitize
it "should sanitize input" do
@@ -12,7 +12,7 @@ module Esapi
# test exception paths
encoder.sanitize("%25",true).should == '%'
encoder.sanitize("%25",false).should == '%'
- # test HTML, url and CSS codecs
+ # test HTML and Percent
encoder.canonicalize("%25F").should == "%F"
encoder.canonicalize("%3c").should == "<"
encoder.canonicalize("%3C").should == "<"
@@ -30,16 +30,6 @@ module Esapi
encoder.canonicalize("%25F").should == "%F"
encoder.canonicalize("%25F").should == "%F"
encoder.canonicalize("%25F").should == "%F"
- encoder.canonicalize("\\3c").should == "<"
- encoder.canonicalize("\\03c").should == "<"
- encoder.canonicalize("\\003c").should == "<"
- encoder.canonicalize("\\0003c").should == "<"
- encoder.canonicalize("\\00003c").should == "<"
- encoder.canonicalize("\\3C").should == "<"
- encoder.canonicalize("\\03C").should == "<"
- encoder.canonicalize("\\003C").should == "<"
- encoder.canonicalize("\\0003C").should == "<"
- encoder.canonicalize("\\00003C").should == "<"
encoder.canonicalize("&#60").should == "<"
encoder.canonicalize("&#060").should == "<"
encoder.canonicalize("&#0060").should == "<"
@@ -90,9 +80,33 @@ module Esapi
begin
encoder.canonicalize("%3Cscript&#x3E;alert%28%22hello&#34%29%3B%3C%2Fscript%3E") == "<script>alert(\"hello\");</script>"
rescue IntrustionException => e
- puts e.log_message
end
- pending("Add JS, Percentage")
+ # javascrpt tests
+ jsencoder = Owasp::Esapi::Encoder.new([Owasp::Esapi::Codec::JavascriptCodec.new])
+ jsencoder.canonicalize("\\0").should == "\0"
+ jsencoder.canonicalize("\\b").should == "\b"
+ jsencoder.canonicalize("\\t").should == "\t"
+ jsencoder.canonicalize("\\n").should == "\n"
+ jsencoder.canonicalize("\\v").should == "\v"
+ jsencoder.canonicalize("\\f").should == "\f"
+ jsencoder.canonicalize("\\r").should == "\r"
+ jsencoder.canonicalize("\\'").should == "\'"
+ jsencoder.canonicalize("\\\"").should == "\""
+ jsencoder.canonicalize("\\\\").should == "\\"
+ jsencoder.canonicalize("\\<").should == "<"
+ # Css test
+ cssencoder = Owasp::Esapi::Encoder.new([Owasp::Esapi::Codec::CssCodec.new])
+ cssencoder.canonicalize("\\3c").should == "<"
+ cssencoder.canonicalize("\\03c").should == "<"
+ cssencoder.canonicalize("\\003c").should == "<"
+ cssencoder.canonicalize("\\0003c").should == "<"
+ cssencoder.canonicalize("\\00003c").should == "<"
+ cssencoder.canonicalize("\\3C").should == "<"
+ cssencoder.canonicalize("\\03C").should == "<"
+ cssencoder.canonicalize("\\003C").should == "<"
+ cssencoder.canonicalize("\\0003C").should == "<"
+ cssencoder.canonicalize("\\00003C").should == "<"
+
end
# Canocialize
it "should canonicalize input" do
View
45 spec/owasp_esapi_javascript_codec_spec.rb
@@ -0,0 +1,45 @@
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+
+module Owasp
+ module Esapi
+ module Codec
+ describe Codec do
+ let (:codec) { Owasp::Esapi::Codec::JavascriptCodec.new }
+
+ it "should decode \\x3c as <" do
+ codec.decode("\\x3c").should == "<"
+ end
+
+ it "should encode < as \\x3C" do
+ codec.encode([],"<").should == "\\x3C"
+ end
+
+ it "should encode 0x100 as \\u0100" do
+ s = 0x100.chr(Encoding::UTF_8)
+ codec.encode([],s[0]).should == "\\u0100"
+ end
+
+ it "should encode <script> as \\x3Cscript\\x3E" do
+ codec.encode(Owasp::Esapi::Encoder::IMMUNE_JAVASCRIPT,"<script>").should == "\\x3Cscript\\x3E"
+ end
+
+ it "should encoder !@$%()=+{}[] as \\x21\\x40\\x24\\x25\\x28\\x29\\x3D\\x2B\\x7B\\x7D\\x5B\\x5D" do
+ codec.encode(Owasp::Esapi::Encoder::IMMUNE_JAVASCRIPT,"!@$%()=+{}[]").should == "\\x21\\x40\\x24\\x25\\x28\\x29\\x3D\\x2B\\x7B\\x7D\\x5B\\x5D"
+ end
+
+ it "shoudl encode ',.-_ ' as ',.\\x2D_\\x20'" do
+ codec.encode(Owasp::Esapi::Encoder::IMMUNE_JAVASCRIPT,",.-_ ").should == ",.\\x2D_\\x20"
+ end
+
+ it "should decode \\f as \f" do
+ codec.decode("\\f").should == "\f"
+ end
+
+ it "should decode \\b as \b" do
+ codec.decode("\\b").should == "\b"
+ end
+
+ end
+ end
+ end
+end
View
39 spec/owasp_esapi_os_codec_spec.rb
@@ -0,0 +1,39 @@
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+
+module Owasp
+ module Esapi
+ module Codec
+ describe Codec do
+ it "should detect the actual host os" do
+ codec = Owasp::Esapi::Codec::OsCodec.new
+ codec.os.should == Owasp::Esapi::Codec::OsCodec::UNIX_HOST
+ end
+ it "should decode ^< as < for windows" do
+ codec = Owasp::Esapi::Codec::OsCodec.new( Owasp::Esapi::Codec::OsCodec::WINDOWS_HOST)
+ codec.decode("^<").should == "<"
+ end
+
+ it "should decode \\< as < for unix" do
+ codec = Owasp::Esapi::Codec::OsCodec.new( Owasp::Esapi::Codec::OsCodec::UNIX_HOST)
+ codec.decode("\\<").should == "<"
+ end
+
+ it "should encode paths properly for windows" do
+ codec = Owasp::Esapi::Codec::OsCodec.new( Owasp::Esapi::Codec::OsCodec::WINDOWS_HOST)
+ codec.encode([],"C:\\jeff").should == "C^:^\\jeff"
+ codec.encode([],"dir & foo").should == "dir^ ^&^ foo"
+
+ end
+
+ it "should encode paths properly for unix" do
+ codec = Owasp::Esapi::Codec::OsCodec.new( Owasp::Esapi::Codec::OsCodec::UNIX_HOST)
+ codec.encode(Owasp::Esapi::Encoder::CHAR_ALPHANUMERIC,"C:\\jeff").should == "C\\:\\\\jeff"
+ codec.encode([],"dir & foo").should == "dir\\ \\&\\ foo"
+ codec.encode(['-'],"/etc/hosts").should == "\\/etc\\/hosts"
+ codec.encode(['-'],"/etc/hosts; ls -l").should == "\\/etc\\/hosts\\;\\ ls\\ -l"
+ end
+
+ end
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.