Class/Module Index [+]

Quicksearch

Brakeman::CheckCrossSiteScripting

This check looks for unescaped output in templates which contains parameters or model attributes.

For example:

<%= User.find(:id).name %>
<%= params[:id] %>

Constants

CGI
FORM_BUILDER
HAML_HELPERS
IGNORE_LIKE
IGNORE_MODEL_METHODS

Model methods which are known to be harmless

MODEL_METHODS
URI
XML_HELPER

Public Instance Methods

actually_process_call(exp) click to toggle source
# File lib/brakeman/checks/check_cross_site_scripting.rb, line 226
def actually_process_call exp
  return if @matched
  target = exp.target
  if sexp? target
    target = process target
  end

  method = exp.method

  #Ignore safe items
  if (target.nil? and (@ignore_methods.include? method or method.to_s =~ IGNORE_LIKE)) or
    (@matched and @matched.type == :model and IGNORE_MODEL_METHODS.include? method) or
    (target == HAML_HELPERS and method == :html_escape) or
    ((target == URI or target == CGI) and method == :escape) or
    (target == XML_HELPER and method == :escape_xml) or
    (target == FORM_BUILDER and @ignore_methods.include? method) or
    (target and @safe_input_attributes.include? method) or
    (method.to_s[-1,1] == "?")

    #exp[0] = :ignore #should not be necessary
    @matched = false
  elsif sexp? target and model_name? target[1] #TODO: use method call?
    @matched = Match.new(:model, exp)
  elsif cookies? exp
    @matched = Match.new(:cookies, exp)
  elsif @inspect_arguments and params? exp
    @matched = Match.new(:params, exp)
  elsif @inspect_arguments
    process_call_args exp
  end
end
check_for_immediate_xss(exp) click to toggle source
# File lib/brakeman/checks/check_cross_site_scripting.rb, line 88
def check_for_immediate_xss exp
  return if duplicate? exp

  if exp.node_type == :output
    out = exp.value
  elsif exp.node_type == :escaped_output and raw_call? exp
    out = exp.value.first_arg
  end

  if input = has_immediate_user_input?(out)
    add_result exp

    case input.type
    when :params
      message = "Unescaped parameter value"
    when :cookies
      message = "Unescaped cookie value"
    when :request
      message = "Unescaped request value"
    else
      message = "Unescaped user input value"
    end

    warn :template => @current_template,
      :warning_type => "Cross Site Scripting",
      :message => message,
      :code => input.match,
      :confidence => CONFIDENCE[:high]

  elsif not tracker.options[:ignore_model_output] and match = has_immediate_model?(out)
    method = if call? match
               match.method
             else
               nil
             end

    unless IGNORE_MODEL_METHODS.include? method
      add_result out

      if MODEL_METHODS.include? method or method.to_s =~ /^find_by/
        confidence = CONFIDENCE[:high]
      else
        confidence = CONFIDENCE[:med]
      end

      message = "Unescaped model attribute"
      link_path = "cross_site_scripting"
      if node_type?(out, :call, :attrasgn) && out.method == :to_json
        message += " in JSON hash"
        link_path += "_to_json"
      end

      code = find_chain out, match
      warn :template => @current_template,
        :warning_type => "Cross Site Scripting",
        :message => message,
        :code => code,
        :confidence => confidence,
        :link_path => link_path
    end

  else
    false
  end
end
process_call(exp) click to toggle source

Check a call for user input

Since we want to report an entire call and not just part of one, use @mark to mark when a call is started. Any dangerous values inside will then report the entire call chain.

# File lib/brakeman/checks/check_cross_site_scripting.rb, line 176
def process_call exp
  if @mark
    actually_process_call exp
  else
    @mark = true
    actually_process_call exp
    message = nil

    if @matched
      case @matched.type
      when :model
        unless tracker.options[:ignore_model_output]
          message = "Unescaped model attribute"
        end
      when :params
        message = "Unescaped parameter value"
      when :cookies
        message = "Unescaped cookie value"
      end

      if message and not duplicate? exp
        add_result exp

        link_path = "cross_site_scripting"
        if @known_dangerous.include? exp.method
          confidence = CONFIDENCE[:high]
          if exp.method == :to_json
            message += " in JSON hash"
            link_path += "_to_json"
          end
        else
          confidence = CONFIDENCE[:low]
        end

        warn :template => @current_template,
          :warning_type => "Cross Site Scripting",
          :message => message,
          :code => exp,
          :user_input => @matched.match,
          :confidence => confidence,
          :link_path => link_path
      end
    end

    @mark = @matched = false
  end

  exp
end
process_cookies(exp) click to toggle source

Note that cookies have been found

# File lib/brakeman/checks/check_cross_site_scripting.rb, line 265
def process_cookies exp
  @matched = Match.new(:cookies, exp)
  exp
end
process_escaped_output(exp) click to toggle source

Look for calls to raw() Otherwise, ignore

# File lib/brakeman/checks/check_cross_site_scripting.rb, line 161
def process_escaped_output exp
  unless check_for_immediate_xss exp
    if raw_call? exp and not duplicate? exp
      process exp.value.first_arg
    end
  end
  exp
end
process_format(exp) click to toggle source

Process as default

# File lib/brakeman/checks/check_cross_site_scripting.rb, line 281
def process_format exp
  process_default exp
end
process_format_escaped(exp) click to toggle source

Ignore output HTML escaped via HAML

# File lib/brakeman/checks/check_cross_site_scripting.rb, line 286
def process_format_escaped exp
  exp
end
process_if(exp) click to toggle source

Ignore condition in if Sexp

# File lib/brakeman/checks/check_cross_site_scripting.rb, line 291
def process_if exp
  process exp.then_clause if sexp? exp.then_clause
  process exp.else_clause if sexp? exp.else_clause
  exp
end
process_output(exp) click to toggle source

Process an output Sexp

# File lib/brakeman/checks/check_cross_site_scripting.rb, line 155
def process_output exp
  process exp.value.dup
end
process_params(exp) click to toggle source

Note that params have been found

# File lib/brakeman/checks/check_cross_site_scripting.rb, line 259
def process_params exp
  @matched = Match.new(:params, exp)
  exp
end
process_render(exp) click to toggle source

Ignore calls to render

# File lib/brakeman/checks/check_cross_site_scripting.rb, line 271
def process_render exp
  exp
end
process_string_interp(exp) click to toggle source

Process as default

# File lib/brakeman/checks/check_cross_site_scripting.rb, line 276
def process_string_interp exp
  process_default exp
end
raw_call?(exp) click to toggle source
# File lib/brakeman/checks/check_cross_site_scripting.rb, line 297
def raw_call? exp
  exp.value.node_type == :call and exp.value.method == :raw
end
run_check() click to toggle source

Run check

# File lib/brakeman/checks/check_cross_site_scripting.rb, line 37
def run_check
  @ignore_methods = Set[:button_to, :check_box, :content_tag, :escapeHTML, :escape_once,
                         :field_field, :fields_for, :h, :hidden_field,
                         :hidden_field, :hidden_field_tag, :image_tag, :label,
                         :link_to, :mail_to, :radio_button, :select,
                         :submit_tag, :text_area, :text_field,
                         :text_field_tag, :url_encode, :url_for,
                         :will_paginate].merge tracker.options[:safe_methods]

  @models = tracker.models.keys
  @inspect_arguments = tracker.options[:check_arguments]

  @known_dangerous = Set[:truncate, :concat]

  if version_between? "2.0.0", "3.0.5"
    @known_dangerous << :auto_link
  elsif version_between? "3.0.6", "3.0.99"
    @ignore_methods << :auto_link
  end

  if version_between? "2.0.0", "2.3.14"
    @known_dangerous << :strip_tags
  end

  json_escape_on = false
  initializers = tracker.check_initializers :ActiveSupport, :escape_html_entities_in_json=
  initializers.each {|result| json_escape_on = true?(result.call.first_arg) }

  if !json_escape_on or version_between? "0.0.0", "2.0.99"
    @known_dangerous << :to_json
    Brakeman.debug("Automatic to_json escaping not enabled, consider to_json dangerous")
  else
    Brakeman.debug("Automatic to_json escaping is enabled.")
  end

  tracker.each_template do |name, template|
    @current_template = template
    template[:outputs].each do |out|
      Brakeman.debug "Checking #{name} for direct XSS"

      unless check_for_immediate_xss out
        Brakeman.debug "Checking #{name} for indirect XSS"

        @matched = false
        @mark = false
        process out
      end
    end
  end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.