提交 607a74b3 编写于 作者: J Justin Collins

Add check for XSS via `content_tag`

上级 dcc2cc2e
require 'brakeman/checks/check_cross_site_scripting'
#Checks for unescaped values in `content_tag`
#
# content_tag :tag, body
# ^-- Unescaped in Rails 2.x
#
# content_tag, :tag, body, attribute => value
# ^-- Unescaped in all versions
#
# content_tag, :tag, body, attribute => value
# ^
# |
# Unescaped by default in 2.x, escaped by default in 3.x,
# can be set by passing in fourth argument
class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
Brakeman::Checks.add self
@description = "Checks for XSS in calls to content_tag"
def run_check
@ignore_methods = Set[:button_to, :check_box, :escapeHTML, :escape_once,
:field_field, :fields_for, :h, :hidden_field,
:hidden_field, :hidden_field_tag, :image_tag, :label,
: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]
@known_dangerous = []
methods = tracker.find_call :target => false, :method => :content_tag
@models = tracker.models.keys
@inspect_arguments = tracker.options[:check_arguments]
Brakeman.debug "Checking for XSS in content_tag"
methods.each do |call|
process_result call
end
end
def process_result result
return if duplicate? result
call = result[:call] = result[:call].dup
args = call.arglist
tag_name = args[1]
content = args[2]
attributes = args[3]
escape_attr = args[4]
@matched = false
#Silly, but still dangerous if someone uses user input in the tag type
check_argument result, tag_name
#Versions before 3.x do not escape body of tag, nor does the rails_xss gem
unless @matched or (tracker.options[:rails3] and not raw? content)
check_argument result, content
end
#Attribute keys are never escaped, so check them for user input
if not @matched and hash? attributes and not request_value? attributes
hash_iterate(attributes) do |k, v|
check_argument result, k
return if @matched
end
end
#By default, content_tag escapes attribute values passed in as a hash.
#But this behavior can be disabled. So only check attributes hash
#if they are explicitly not escaped.
if not @matched and attributes and false? escape_attr
if request_value? attributes or not hash? attributes
check_argument result, attributes
else #check hash values
hash_iterate(attributes) do |k, v|
check_argument result, v
return if @matched
end
end
end
end
def check_argument result, exp
#Check contents of raw() calls directly
if call? exp and exp.method == :raw
arg = process exp.first_arg
else
arg = process exp
end
if input = has_immediate_user_input?(arg)
case input.type
when :params
message = "Unescaped parameter value in content_tag"
when :cookies
message = "Unescaped cookie value in content_tag"
else
message = "Unescaped user input value in content_tag"
end
add_result result
warn :result => result,
:warning_type => "Cross Site Scripting",
:message => message,
:user_input => input.match,
:confidence => CONFIDENCE[:high],
:link_path => "content_tag"
elsif not tracker.options[:ignore_model_output] and match = has_immediate_model?(arg)
method = match[2]
unless IGNORE_MODEL_METHODS.include? method
add_result result
if MODEL_METHODS.include? method or method.to_s =~ /^find_by/
confidence = CONFIDENCE[:high]
else
confidence = CONFIDENCE[:med]
end
warn :result => result,
:warning_type => "Cross Site Scripting",
:message => "Unescaped model attribute in content_tag",
:user_input => match,
:confidence => confidence,
:link_path => "content_tag"
end
elsif @matched
message = "Unescaped "
case @matched.type
when :model
return if tracker.options[:ignore_model_output]
message << "model attribute"
when :params
message << "parameter"
when :cookies
message << "cookie"
when :session
message << "session"
else
message << "user input"
end
message << " value in content_tag"
add_result result
warn :result => result,
:warning_type => "Cross Site Scripting",
:message => message,
:user_input => @matched.match,
:confidence => CONFIDENCE[:med],
:link_path => "content_tag"
end
end
def process_call exp
if @mark
actually_process_call exp
else
@mark = true
actually_process_call exp
@mark = false
end
exp
end
def raw? exp
call? exp and exp.method == :raw
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册