|
| 1 | +<!DOCTYPE qhelp PUBLIC |
| 2 | + "-//Semmle//qhelp//EN" |
| 3 | + "qhelp.dtd"> |
| 4 | +<qhelp> |
| 5 | + |
| 6 | +<overview> |
| 7 | +<p> |
| 8 | +Sanitizing untrusted input is a common technique for preventing injection attacks such as SQL |
| 9 | +injection or cross-site scripting. Usually, this is done by escaping meta-characters such as quotes |
| 10 | +in a domain-specific way so that they are treated as normal characters. |
| 11 | +</p> |
| 12 | +<p> |
| 13 | +However, directly using the <code>String#sub</code> method to perform escaping is notoriously |
| 14 | +error-prone. Common mistakes include only replacing the first occurrence of a meta-character, or |
| 15 | +backslash-escaping various meta-characters but not the backslash itself. |
| 16 | +</p> |
| 17 | +<p> |
| 18 | +In the former case, later meta-characters are left undisturbed and can be used to subvert the |
| 19 | +sanitization. In the latter case, preceding a meta-character with a backslash leads to the backslash |
| 20 | +being escaped, but the meta-character appearing un-escaped, which again makes the sanitization |
| 21 | +ineffective. |
| 22 | +</p> |
| 23 | +<p> |
| 24 | +Even if the escaped string is not used in a security-critical context, incomplete escaping may still |
| 25 | +have undesirable effects, such as badly rendered or confusing output. |
| 26 | +</p> |
| 27 | +</overview> |
| 28 | + |
| 29 | +<recommendation> |
| 30 | +<p> |
| 31 | +Use a (well-tested) sanitization library if at all possible. These libraries are much more likely to |
| 32 | +handle corner cases correctly than a custom implementation. |
| 33 | +</p> |
| 34 | + |
| 35 | +<p> |
| 36 | +An even safer alternative is to design the application so that sanitization is not needed. |
| 37 | +Otherwise, make sure to use <code>String#gsub</code> rather than <code>String#sub</code>, to ensure |
| 38 | +that all occurrences are replaced, and remember to escape backslashes if applicable. |
| 39 | +</p> |
| 40 | +<p> |
| 41 | +Note, however, that this is generally <i>not</i> sufficient for replacing multi-character strings: |
| 42 | +the <code>String#gsub</code> method performs only one pass over the input string, and will not |
| 43 | +replace further instances of the string that result from earlier replacements. |
| 44 | +</p> |
| 45 | +<p> |
| 46 | +For example, consider the code snippet <code>s.gsub /\/\.\.\//, ""</code>, which attempts to strip |
| 47 | +out all occurences of <code>/../</code> from <code>s</code>. This will not work as expected: for the |
| 48 | +string <code>/./.././</code>, for example, it will remove the single occurrence of <code>/../</code> |
| 49 | +in the middle, but the remainder of the string then becomes <code>/../</code>, which is another |
| 50 | +instance of the substring we were trying to remove. |
| 51 | +</p> |
| 52 | +</recommendation> |
| 53 | + |
| 54 | +<example> |
| 55 | +<p> |
| 56 | +As an example, assume that we want to embed a user-controlled string <code>account_number</code> into |
| 57 | +a SQL query as part of a string literal. To avoid SQL injection, we need to ensure that the string |
| 58 | +does not contain un-escaped single-quote characters. The following method attempts to ensure this by |
| 59 | +doubling single quotes, and thereby escaping them: |
| 60 | +</p> |
| 61 | + |
| 62 | +<sample src="examples/IncompleteSanitization.rb" /> |
| 63 | + |
| 64 | +<p> |
| 65 | +As written, this sanitizer is ineffective: <code>String#sub</code> will replace only the |
| 66 | +<i>first</i> occurrence of that string. |
| 67 | +</p> |
| 68 | + |
| 69 | +<p> |
| 70 | +As mentioned above, the method <code>escape_quotes</code> should be replaced with a purpose-built |
| 71 | +sanitizer, such as <code>ActiveRecord::Base::sanitize_sql</code> in Rails, or by using ORM methods |
| 72 | +that automatically sanitize parameters. |
| 73 | +</p> |
| 74 | + |
| 75 | +<p> |
| 76 | +If this is not an option, <code>escape_quotes</code> should be rewritten to use the |
| 77 | +<code>String#gsub</code> method instead: |
| 78 | +</p> |
| 79 | + |
| 80 | +<sample src="examples/IncompleteSanitizationGood.rb" /> |
| 81 | +</example> |
| 82 | + |
| 83 | +<references> |
| 84 | +<li>OWASP Top 10: <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection">A1 Injection</a>.</li> |
| 85 | +<li>Rails: <a href="https://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html">ActiveRecord::Base::sanitize_sql</a>.</li> |
| 86 | +</references> |
| 87 | +</qhelp> |
0 commit comments