Class: WSDL::XML::ThreatScanner Private
- Inherits:
-
Object
- Object
- WSDL::XML::ThreatScanner
- Defined in:
- lib/wsdl/xml/threat_scanner.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
Scans raw XML strings for attack patterns without parsing.
Provides defense-in-depth threat detection by identifying suspicious patterns before they reach the parser. All scanning operates on binary-encoded strings using byte-level comparisons to avoid allocations from regex match objects.
Detected threats:
- +:doctype+ — DOCTYPE declaration (XXE vector)
- +:entity_declaration+ — ENTITY definitions
- +:external_reference+ — SYSTEM or PUBLIC identifiers
- +:parameter_entity+ — Parameter entity references (+%entity;+)
- +:deep_nesting+ — Excessive open tags (>MAX_OPEN_TAGS)
- +:large_attribute+ — Single attribute value >MAX_ATTRIBUTE_VALUE_SIZE bytes
- +:large_attributes_total+ — Cumulative attribute size >MAX_TOTAL_ATTRIBUTE_SIZE bytes
Byte Constants collapse
- SLASH_BYTE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
'/'.ord
- BANG_BYTE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
'!'.ord
- QUESTION_BYTE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
'?'.ord
- DOUBLE_QUOTE_BYTE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
'"'.ord
- SINGLE_QUOTE_BYTE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
"'".ord
- WHITESPACE_BYTES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Whitespace byte values: space, tab, LF, CR.
Set[0x20, 0x09, 0x0A, 0x0D].freeze
- QUOTE_BYTES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Quote byte values: double quote and single quote.
Set[DOUBLE_QUOTE_BYTE, SINGLE_QUOTE_BYTE].freeze
- NON_OPEN_TAG_BYTES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Non-open-tag byte values: closing (+/+), declaration (+!+), processing instruction (+?+).
Set[SLASH_BYTE, BANG_BYTE, QUESTION_BYTE].freeze
- QUOTE_CHARS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Pre-computed binary quote character strings, keyed by byte value. Avoids allocating a new String via +Integer#chr+ on every call.
{ DOUBLE_QUOTE_BYTE => '"'.b.freeze, SINGLE_QUOTE_BYTE => "'".b.freeze }.freeze
Constant Summary collapse
- MAX_OPEN_TAGS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Maximum number of open tags before flagging deep nesting.
1_000- MAX_ATTRIBUTE_VALUE_SIZE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Maximum size of a single attribute value in bytes.
10_000- MAX_TOTAL_ATTRIBUTE_SIZE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Maximum cumulative size of all attribute values in bytes.
1_000_000
Instance Method Summary collapse
-
#count_open_tags ⇒ Integer
private
Counts open XML tags using byte-level scanning.
-
#initialize(xml_string) ⇒ ThreatScanner
constructor
private
A new instance of ThreatScanner.
-
#scan ⇒ Array<Symbol>
private
Scans for all threat patterns and returns unique threat symbols.
-
#scan_attribute_threats ⇒ Array<Symbol>
private
Scans attribute values for size-based threats.
Constructor Details
#initialize(xml_string) ⇒ ThreatScanner
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of ThreatScanner.
76 77 78 |
# File 'lib/wsdl/xml/threat_scanner.rb', line 76 def initialize(xml_string) @bin = xml_string.b end |
Instance Method Details
#count_open_tags ⇒ Integer
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Counts open XML tags using byte-level scanning.
Matches tags that start with an ASCII letter and are not closing tags (+</+), comments (+<!+), or processing instructions (+<?+).
103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/wsdl/xml/threat_scanner.rb', line 103 def count = 0 pos = 0 while (pos = @bin.index('<', pos)) byte = @bin.getbyte(pos + 1) count += 1 if open_tag_start?(byte) pos += 1 end count end |
#scan ⇒ Array<Symbol>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Scans for all threat patterns and returns unique threat symbols.
83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/wsdl/xml/threat_scanner.rb', line 83 def scan threats = [] threats << :doctype if @bin.match?(/<!DOCTYPE/i) threats << :entity_declaration if @bin.match?(/<!ENTITY/i) threats << :external_reference if @bin.match?(/\bSYSTEM\s+["']/i) threats << :external_reference if @bin.match?(/\bPUBLIC\s+["']/i) threats << :parameter_entity if @bin.match?(/%[a-zA-Z_][a-zA-Z0-9_]*;/) threats << :deep_nesting if > MAX_OPEN_TAGS threats.concat(scan_attribute_threats) threats.uniq end |
#scan_attribute_threats ⇒ Array<Symbol>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Scans attribute values for size-based threats.
Locates +=+ followed by a quoted string, then measures each value's length via position arithmetic (zero allocations).
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/wsdl/xml/threat_scanner.rb', line 122 def scan_attribute_threats threats = [] total_size = 0 pos = 0 while pos < @bin.size eq_pos = @bin.index('=', pos) break unless eq_pos measure_attribute_value(eq_pos) pos = @measured_next_pos next unless @measured_value_length total_size += @measured_value_length threats << :large_attribute if @measured_value_length > MAX_ATTRIBUTE_VALUE_SIZE end threats << :large_attributes_total if total_size > MAX_TOTAL_ATTRIBUTE_SIZE threats end |