Class: Aikido::Zen::Scanners::SQLInjectionScanner
- Inherits:
-
Object
- Object
- Aikido::Zen::Scanners::SQLInjectionScanner
- Defined in:
- lib/aikido/zen/scanners/sql_injection_scanner.rb
Defined Under Namespace
Classes: Dialect
Constant Summary collapse
- DIALECTS =
Maps easy-to-use Symbols to a struct that keeps both the name and the internal identifier used by libzen.
{ common: Dialect.new(name: "SQL", internals_key: 0), mysql: Dialect.new(name: "MySQL", internals_key: 8), postgresql: Dialect.new(name: "PostgreSQL", internals_key: 9), sqlite: Dialect.new(name: "SQLite", internals_key: 12) }
Class Method Summary collapse
-
.call(query:, dialect:, sink:, context:, operation:) ⇒ Aikido::Zen::Attack?
Checks if the given SQL query may have dangerous user input injected, and returns an Attack if so, based on the current request.
Instance Method Summary collapse
- #attack? ⇒ Boolean
-
#initialize(query, input, dialect) ⇒ SQLInjectionScanner
constructor
A new instance of SQLInjectionScanner.
Constructor Details
#initialize(query, input, dialect) ⇒ SQLInjectionScanner
Returns a new instance of SQLInjectionScanner.
52 53 54 55 56 |
# File 'lib/aikido/zen/scanners/sql_injection_scanner.rb', line 52 def initialize(query, input, dialect) @query = query.downcase @input = input.downcase @dialect = dialect end |
Class Method Details
.call(query:, dialect:, sink:, context:, operation:) ⇒ Aikido::Zen::Attack?
Checks if the given SQL query may have dangerous user input injected, and returns an Attack if so, based on the current request.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/aikido/zen/scanners/sql_injection_scanner.rb', line 24 def self.call(query:, dialect:, sink:, context:, operation:) # FIXME: This assumes queries executed outside of an HTTP request are # safe, but this is not the case. For example, if an HTTP request # enqueues a background job, passing user input verbatim, the job might # pass that input to a query without having a current request in scope. return if context.nil? dialect = DIALECTS.fetch(dialect) do Aikido::Zen.config.logger.warn "Unknown SQL dialect #{dialect.inspect}" DIALECTS[:common] end context.payloads.each do |payload| next unless new(query, payload.value, dialect).attack? return Attacks::SQLInjectionAttack.new( sink: sink, query: query, input: payload, dialect: dialect, context: context, operation: "#{sink.operation}.#{operation}" ) end nil end |
Instance Method Details
#attack? ⇒ Boolean
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/aikido/zen/scanners/sql_injection_scanner.rb', line 58 def attack? # Ignore single char inputs since they shouldn't be able to do much harm return false if @input.length <= 1 # If the input is longer than the query, then it is not part of it return false if @input.length > @query.length # If the input is not included in the query at all, then we are safe return false unless @query.include?(@input) # If the input is solely alphanumeric, we can ignore it return false if /\A[[:alnum:]_]+\z/i.match?(@input) # If the input is a comma-separated list of numbers, ignore it. return false if /\A(?:\d+(?:,\s*)?)+\z/i.match?(@input) Internals.detect_sql_injection(@query, @input, @dialect) end |