Copyright (c) 2012-2013, Coverity, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
- Neither the name of Coverity, Inc. nor the names of its contributors may be used
to endorse or promote products derived from this software without specific prior
written permission from Coverity, Inc.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND INFRINGEMENT ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
/**
* Copyright (c) 2012-2013, Coverity, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* - Neither the name of Coverity, Inc. nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* written permission from Coverity, Inc.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND INFRINGEMENT ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
package com.coverity.security;
Escape is a small set of methods for escaping tainted data. These escaping
methods are useful in transforming user-controlled ("tainted") data into
forms that are safe from being interpreted as something other than data, such
as JavaScript.
At this time most of these escaping routines focus on cross-site scripting
mitigations. Each method is good for a different HTML context. For a primer
on HTML contexts, see OWASP's XSS Prevention Cheat Sheet (note however that
the escaping routines are not implemented exactly according to OWASP's
recommendations) or the Coverity Security Advisor documentation.
Also see the Coverity Security Research Laboratory blog on
how to properly use each function.
While Coverity's static analysis product references these escaping routines
as exemplars and understands their behavior, there is no dependency on
Coverity products and these routines are completely standalone. Feel free to
use them! Just make sure you use them correctly.
Author: Romain Gaucher, Andy Chou, Jon Passki, Alex Kouzemtchenko
/**
* Escape is a small set of methods for escaping tainted data. These escaping
* methods are useful in transforming user-controlled ("tainted") data into
* forms that are safe from being interpreted as something other than data, such
* as JavaScript.
* <p>
* At this time most of these escaping routines focus on cross-site scripting
* mitigations. Each method is good for a different HTML context. For a primer
* on HTML contexts, see OWASP's XSS Prevention Cheat Sheet (note however that
* the escaping routines are not implemented exactly according to OWASP's
* recommendations) or the Coverity Security Advisor documentation.
* Also see the Coverity Security Research Laboratory blog on
* how to properly use each function.
* <p>
* While Coverity's static analysis product references these escaping routines
* as exemplars and understands their behavior, there is no dependency on
* Coverity products and these routines are completely standalone. Feel free to
* use them! Just make sure you use them correctly.
*
* @author Romain Gaucher
* @author Andy Chou
* @author Jon Passki
* @author Alex Kouzemtchenko
*
*/
public class Escape {
HTML entity escaping for text content and attributes.
HTML entity escaping that is appropriate for the most common HTML contexts:
PCDATA and "normal" attributes (non-URI, non-event, and non-CSS attributes).
Note that we do not recommend using non-quoted HTML attributes since
the security obligations vary more between web browser. We recommend
to always quote (single or double quotes) HTML attributes.
This method is generic to HTML entity escaping, and therefore escapes more characters than usually necessary -- mostly to handle non-quoted attribute values. If this method is somehow too slow, such as you output megabytes of text with spaces, please use the htmlText(String)
method which only escape HTML text specific characters.
The following characters are escaped:
-
HTML characters:
' (U+0022)
, " (U+0027)
,
\ (U+005C)
, / (U+002F)
,
< (U+003C)
, > (U+003E)
,
& (U+0026)
-
Control characters:
\t (U+0009)
, \n (U+000A)
,
\f (U+000C)
, \r (U+000D)
,
SPACE (U+0020)
-
Unicode newlines:
LS (U+2028)
, PS (U+2029)
Params: - input – the string to be escaped
Returns: the HTML escaped string or null
if input
is null Since: 1.0
/**
* HTML entity escaping for text content and attributes.
* <p>
* HTML entity escaping that is appropriate for the most common HTML contexts:
* PCDATA and "normal" attributes (non-URI, non-event, and non-CSS attributes). <br />
* Note that we do not recommend using non-quoted HTML attributes since
* the security obligations vary more between web browser. We recommend
* to always quote (single or double quotes) HTML attributes.<br />
* This method is generic to HTML entity escaping, and therefore escapes more
* characters than usually necessary -- mostly to handle non-quoted attribute values.
* If this method is somehow too slow, such as you output megabytes of text with spaces,
* please use the {@link #htmlText(String)} method which only escape HTML text specific
* characters.
*
* <p>
* The following characters are escaped:
* <ul>
* <li>
* HTML characters: <code>' (U+0022)</code>, <code>" (U+0027)</code>,
* <code>\ (U+005C)</code>, <code>/ (U+002F)</code>,
* <code>< (U+003C)</code>, <code>> (U+003E)</code>,
* <code>& (U+0026)</code>
* </li>
* <li>
* Control characters: <code>\t (U+0009)</code>, <code>\n (U+000A)</code>,
* <code>\f (U+000C)</code>, <code>\r (U+000D)</code>,
* <code>SPACE (U+0020)</code>
* </li>
* <li>
* Unicode newlines: <code>LS (U+2028)</code>, <code>PS (U+2029)</code>
* </li>
* </ul>
*
* @param input the string to be escaped
* @return the HTML escaped string or <code>null</code> if <code>input</code> is null
* @since 1.0
*/
public static String html(String input) {
if (input == null)
return null;
int length = input.length();
StringBuilder output = allocateStringBuilder(length);
for (int i = 0; i < length; i++) {
char c = input.charAt(i);
switch (c) {
// Control chars
case '\t':
output.append("	");
break;
case '\n':
output.append("
");
break;
case '\f':
output.append("");
break;
case '\r':
output.append("
");
break;
// Chars that have a meaning for HTML
case '\'':
output.append("'");
break;
case '\\':
output.append("\");
break;
case ' ':
output.append(" ");
break;
case '/':
output.append("/");
break;
case '"':
output.append(""");
break;
case '<':
output.append("<");
break;
case '>':
output.append(">");
break;
case '&':
output.append("&");
break;
// Unicode new lines
case '\u2028':
output.append("
");
break;
case '\u2029':
output.append("
");
break;
default:
output.append(c);
break;
}
}
return output.toString();
}
Faster HTML entity escaping for tag content or quoted attributes values only.
HTML entity escaping that is specific to text elements such as the content of
a typical HTML tag (div
, p
, etc.).
This method is not appropriate in all cases, and especially when appending data
in a non-quoted context (e.g., an HTML attribute value that is not surrounded by
single or double quotes). Note that we however, highly discourage the use
of non-quoted attributes.
The following characters are escaped:
-
HTML characters:
' (U+0022)
, " (U+0027)
,
< (U+003C)
, > (U+003E)
,
& (U+0026)
Params: - input – the string to be escaped
Returns: the HTML escaped string or null
if input
is null Since: 1.0
/**
* Faster HTML entity escaping for tag content or quoted attributes values only.
* <p>
* HTML entity escaping that is specific to text elements such as the content of
* a typical HTML tag (<code>div</code>, <code>p</code>, etc.).<br />
* This method is not appropriate in all cases, and especially when appending data
* in a non-quoted context (e.g., an HTML attribute value that is not surrounded by
* single or double quotes). Note that we however, highly discourage the use
* of non-quoted attributes.
*
* <p>
* The following characters are escaped:
* <ul>
* <li>
* HTML characters: <code>' (U+0022)</code>, <code>" (U+0027)</code>,
* <code>< (U+003C)</code>, <code>> (U+003E)</code>,
* <code>& (U+0026)</code>
* </li>
* </ul>
*
* @param input the string to be escaped
* @return the HTML escaped string or <code>null</code> if <code>input</code> is null
* @since 1.0
*/
public static String htmlText(String input) {
if (input == null)
return null;
int length = input.length();
StringBuilder output = allocateStringBuilder(length);
for (int i = 0; i < length; i++) {
char c = input.charAt(i);
switch (c) {
case '\'':
output.append("'");
break;
case '"':
output.append(""");
break;
case '<':
output.append("<");
break;
case '>':
output.append(">");
break;
case '&':
output.append("&");
break;
default:
output.append(c);
break;
}
}
return output.toString();
}
URI encoder.
URI encoding for query string values of the URI:
/example/?name=URI_ENCODED_VALUE_HERE
Note that this method is not sufficient to protect for cross-site scripting
in a generic URI context, but only for query string values. If you
need to escape a URI in an href
attribute (for example),
ensure that:
- The scheme is allowed (restrict to http, https, or mailto)
- Use the HTML escaper
html(String)
on the entire URI
This URI encoder processes the following characters:
-
URI characters:
' (U+0022)
, " (U+0027)
,
\ (U+005C)
, / (U+002F)
,
< (U+003C)
, > (U+003E)
,
& (U+0026)
,
< (U+003C)
, > (U+003E)
,
! (U+0021)
, # (U+0023)
,
$ (U+0024)
, % (U+0025)
,
( (U+0028)
, ) (U+0029)
,
* (U+002A)
, + (U+002B)
,
, (U+002C)
, . (U+002E)
,
: (U+003A)
, ; (U+003B)
,
= (U+003D)
, ? (U+003F)
,
@ (U+0040)
, [ (U+005B)
,
] (U+005D)
-
Control characters:
\t (U+0009)
, \n (U+000A)
,
\f (U+000C)
, \r (U+000D)
,
SPACE (U+0020)
Params: - input – the string to be escaped
Returns: the URI encoded string or null
if input
is null Since: 1.0
/**
* URI encoder.
* <p>
* URI encoding for query string values of the URI:
* <code>/example/?name=URI_ENCODED_VALUE_HERE</code> <br />
* Note that this method is not sufficient to protect for cross-site scripting
* in a generic URI context, but only for query string values. If you
* need to escape a URI in an <code>href</code> attribute (for example),
* ensure that:
* <ul>
* <li>The scheme is allowed (restrict to http, https, or mailto)</li>
* <li>Use the HTML escaper {@link #html(String)} on the entire URI</li>
* </ul>
* <p>
* This URI encoder processes the following characters:
* <ul>
* <li>
* URI characters: <code>' (U+0022)</code>, <code>" (U+0027)</code>,
* <code>\ (U+005C)</code>, <code>/ (U+002F)</code>,
* <code>< (U+003C)</code>, <code>> (U+003E)</code>,
* <code>& (U+0026)</code>,
* <code>< (U+003C)</code>, <code>> (U+003E)</code>,
* <code>! (U+0021)</code>, <code># (U+0023)</code>,
* <code>$ (U+0024)</code>, <code>% (U+0025)</code>,
* <code>( (U+0028)</code>, <code>) (U+0029)</code>,
* <code>* (U+002A)</code>, <code>+ (U+002B)</code>,
* <code>, (U+002C)</code>, <code>. (U+002E)</code>,
* <code>: (U+003A)</code>, <code>; (U+003B)</code>,
* <code>= (U+003D)</code>, <code>? (U+003F)</code>,
* <code>@ (U+0040)</code>, <code>[ (U+005B)</code>,
* <code>] (U+005D)</code>
* </li>
* <li>
* Control characters: <code>\t (U+0009)</code>, <code>\n (U+000A)</code>,
* <code>\f (U+000C)</code>, <code>\r (U+000D)</code>,
* <code>SPACE (U+0020)</code>
* </li>
* </ul>
*
* @param input the string to be escaped
* @return the URI encoded string or <code>null</code> if <code>input</code> is null
* @since 1.0
*/
public static String uriParam(String input) {
if (input == null)
return null;
int length = input.length();
StringBuilder output = allocateStringBuilder(length);
for (int i = 0; i < length; i++) {
char c = input.charAt(i);
switch (c) {
// Control chars
case '\t':
output.append("%09");
break;
case '\n':
output.append("%0A");
break;
case '\f':
output.append("%0C");
break;
case '\r':
output.append("%0D");
break;
// RFC chars to encode, plus % ' " < and >, and space
case ' ':
output.append("%20");
break;
case '!':
output.append("%21");
break;
case '"':
output.append("%22");
break;
case '#':
output.append("%23");
break;
case '$':
output.append("%24");
break;
case '%':
output.append("%25");
break;
case '&':
output.append("%26");
break;
case '\'':
output.append("%27");
break;
case '(':
output.append("%28");
break;
case ')':
output.append("%29");
break;
case '*':
output.append("%2A");
break;
case '+':
output.append("%2B");
break;
case ',':
output.append("%2C");
break;
case '.':
output.append("%2E");
break;
case '/':
output.append("%2F");
break;
case ':':
output.append("%3A");
break;
case ';':
output.append("%3B");
break;
case '<':
output.append("%3C");
break;
case '=':
output.append("%3D");
break;
case '>':
output.append("%3E");
break;
case '?':
output.append("%3F");
break;
case '@':
output.append("%40");
break;
case '[':
output.append("%5B");
break;
case ']':
output.append("%5D");
break;
default:
output.append(c);
break;
}
}
return output.toString();
}
Same as uriParam(String)
for now.
Eventually, this method will evolve into filtering the URI so that
it is safely considered as a URL by a web browser, and does not contain
malicious payloads (data:text/html..., javascript:, etc.).
/**
* Same as {@link #uriParam(String)} for now.
* <p>
* Eventually, this method will evolve into filtering the URI so that
* it is safely considered as a URL by a web browser, and does not contain
* malicious payloads (data:text/html..., javascript:, etc.).
*/
public static String uri(String input) {
return uriParam(input);
}
JavaScript String Unicode escaper.
JavaScript String Unicode escaping (\UXXXX
) to be used in single or double quoted
JavaScript strings:
<script type="text/javascript">
window.myString = 'JS_STRING_ESCAPE_HERE';
window.yourString = "JS_STRING_ESCAPE_HERE";
</script>
This JavaScript string escaper processes the following characters:
-
JS String characters:
' (U+0022)
, " (U+0027)
,
\ (U+005C)
-
URI encoding characters:
% (U+0025)
-
HTML characters:
/ (U+002F)
,
< (U+003C)
, > (U+003E)
,
& (U+0026)
-
Control characters:
\b (U+0008)
, \t (U+0009)
,
\n (U+000A)
, 0x0b (U+000B)
,
\f (U+000C)
, \r (U+000D)
-
Unicode newlines:
LS (U+2028)
, PS (U+2029)
Params: - input – the string to be escaped
Returns: the JavaScript string Unicode escaped string or null
if input
is null Since: 1.0
/**
* JavaScript String Unicode escaper.
* <p>
* JavaScript String Unicode escaping (<code>\UXXXX</code>) to be used in single or double quoted
* JavaScript strings:
* <pre>
* <script type="text/javascript">
* window.myString = 'JS_STRING_ESCAPE_HERE';
* window.yourString = "JS_STRING_ESCAPE_HERE";
* </script>
* </pre>
* <p>
* This JavaScript string escaper processes the following characters:
* <ul>
* <li>
* JS String characters: <code>' (U+0022)</code>, <code>" (U+0027)</code>,
* <code>\ (U+005C)</code>
* </li>
* <li>
* URI encoding characters: <code>% (U+0025)</code>
* </li>
* <li>
* HTML characters: <code>/ (U+002F)</code>,
* <code>< (U+003C)</code>, <code>> (U+003E)</code>,
* <code>& (U+0026)</code>
* </li>
* <li>
* Control characters: <code>\b (U+0008)</code>, <code>\t (U+0009)</code>,
* <code>\n (U+000A)</code>, <code>0x0b (U+000B)</code>,
* <code>\f (U+000C)</code>, <code>\r (U+000D)</code>
* </li>
* <li>
* Unicode newlines: <code>LS (U+2028)</code>, <code>PS (U+2029)</code>
* </li>
* </ul>
*
* @param input the string to be escaped
* @return the JavaScript string Unicode escaped string or <code>null</code> if <code>input</code> is null
* @since 1.0
*/
public static String jsString(String input) {
if (input == null)
return null;
int length = input.length();
StringBuilder output = allocateStringBuilder(length);
for (int i = 0; i < length; i++) {
char c = input.charAt(i);
switch (c) {
// Control chars
case '\b':
output.append("\\u0008");
break;
case '\t':
output.append("\\u0009");
break;
case '\n':
output.append("\\u000A");
break;
case '\u000b':
output.append("\\u000B");
break;
case '\f':
output.append("\\u000C");
break;
case '\r':
output.append("\\u000D");
break;
// JavaScript String chars
case '\'':
output.append("\\u0027");
break;
case '"':
output.append("\\u0022");
break;
case '\\':
output.append("\\u005C");
break;
// URI encoding char
case '%':
output.append("\\u0025");
break;
// HTML chars for closing the parent context
case '&':
output.append("\\u0026");
break;
case '/':
output.append("\\u002F");
break;
case '<':
output.append("\\u003C");
break;
case '>':
output.append("\\u003E");
break;
// Unicode
case '\u2028':
output.append("\\u2028");
break;
case '\u2029':
output.append("\\u2029");
break;
default:
output.append(c);
break;
}
}
return output.toString();
}
JavaScript regex content escaper.
Escape for a JavaScript regular expression:
<script type="text/javascript">
var b = /^JS_REGEX_ESCAPE_HERE/.test(document.location);
</script>
Note that when using a regular expression inside a JavaScript string such as:
<script type="text/javascript">
var b = (new RegExp('^CONTENT_HERE')).test(document.location);
</script>
You should first escape using the jsRegex(String)
escaper, and make sure that the JavaScript string itself is properly rendered using the jsString(String)
escaper. This is a nested context scenario in which we have a JavaScript regex inside a JavaScript string, for which we need to first escape the inner most context and walking back the stack of context to the outer most one.
This JavaScript regex escaper processes the following characters:
-
Regex characters:
\ (U+005C)
, / (U+002F)
,
( (U+0028)
, [ (U+005B)
,
{ (U+007B)
, ] (U+005D)
,
} (U+007D)
, ) (U+0029)
,
* (U+002A)
, + (U+002B)
,
- (U+002D)
, . (U+002E)
,
? (U+003F)
, ! (U+0021)
,
^ (U+005E)
, $ (U+0024)
,
| (U+007C)
-
Control characters:
\t (U+0009)
, \n (U+000A)
,
\v (U+000B)
,
\f (U+000C)
, \r (U+000D)
Params: - input – the string to be escaped
Returns: the escaped JavaScript regex or null
if input
is null Since: 1.0
/**
* JavaScript regex content escaper.
* <p>
* Escape for a JavaScript regular expression:
* <pre>
* <script type="text/javascript">
* var b = /^JS_REGEX_ESCAPE_HERE/.test(document.location);
* </script>
* </pre>
* <p>
* Note that when using a regular expression inside a JavaScript string such as:
* <pre><script type="text/javascript">
* var b = (new RegExp('^CONTENT_HERE')).test(document.location);
* </script></pre>
* You should first escape using the {@link #jsRegex(String)} escaper, and make sure
* that the JavaScript string itself is properly rendered using the {@link #jsString(String)}
* escaper. This is a nested context scenario in which we have a JavaScript regex
* inside a JavaScript string, for which we need to first escape the inner most context
* and walking back the stack of context to the outer most one.
* </p>
* <p>
* This JavaScript regex escaper processes the following characters:
* <ul>
* <li>
* Regex characters: <code>\ (U+005C)</code>, <code>/ (U+002F)</code>,
* <code>( (U+0028)</code>, <code>[ (U+005B)</code>,
* <code>{ (U+007B)</code>, <code>] (U+005D)</code>,
* <code>} (U+007D)</code>, <code>) (U+0029)</code>,
* <code>* (U+002A)</code>, <code>+ (U+002B)</code>,
* <code>- (U+002D)</code>, <code>. (U+002E)</code>,
* <code>? (U+003F)</code>, <code>! (U+0021)</code>,
* <code>^ (U+005E)</code>, <code>$ (U+0024)</code>,
* <code>| (U+007C)</code>
* </li>
* <li>
* Control characters: <code>\t (U+0009)</code>, <code>\n (U+000A)</code>,
* <code>\v (U+000B)</code>,
* <code>\f (U+000C)</code>, <code>\r (U+000D)</code>
* </li>
* </ul>
*
* @param input the string to be escaped
* @return the escaped JavaScript regex or <code>null</code> if <code>input</code> is null
* @since 1.0
*/
public static String jsRegex(String input) {
if (input == null)
return null;
int length = input.length();
StringBuilder output = allocateStringBuilder(length);
for (int i = 0; i < length; i++) {
char c = input.charAt(i);
switch (c) {
// Control chars
case '\t':
output.append("\\t");
break;
case '\n':
output.append("\\n");
break;
case '\u000b':
output.append("\\v");
break;
case '\f':
output.append("\\f");
break;
case '\r':
output.append("\\r");
break;
// Escape sequence, and regexp terminator
case '\\':
output.append("\\\\");
break;
case '/':
output.append("\\/");
break;
// Regexp specific characters
case '(':
output.append("\\(");
break;
case '[':
output.append("\\[");
break;
case '{':
output.append("\\{");
break;
case ']':
output.append("\\]");
break;
case ')':
output.append("\\)");
break;
case '}':
output.append("\\}");
break;
case '*':
output.append("\\*");
break;
case '+':
output.append("\\+");
break;
case '-':
output.append("\\-");
break;
case '.':
output.append("\\.");
break;
case '?':
output.append("\\?");
break;
case '!':
output.append("\\!");
break;
case '^':
output.append("\\^");
break;
case '$':
output.append("\\$");
break;
case '|':
output.append("\\|");
break;
default:
output.append(c);
break;
}
}
return output.toString();
}
CSS String escaper.
CSS escaper for strings such as CSS selector or quoted URI:
<style">
a[href *= "DATA_HERE"] {...}
li { background: url('DATA_HERE'); }
</style>
This CSS string escaper processes the following characters:
-
CSS string characters:
' (U+0022)
, " (U+0027)
,
\ (U+005C)
-
HTML characters:
/ (U+002F)
,
< (U+003C)
, > (U+003E)
,
& (U+0026)
-
Control characters:
\b (U+0008)
,
\t (U+0009)
, \n (U+000A)
,
\f (U+000C)
, \r (U+000D)
-
Unicode newlines:
LS (U+2028)
, PS (U+2029)
Params: - input – the string to be escaped
Returns: the CSS string escaped or null
if input
is null Since: 1.0
/**
* CSS String escaper.
* <p>
* CSS escaper for strings such as CSS selector or quoted URI:
* <pre>
* <style">
* a[href *= "DATA_HERE"] {...}
* li { background: url('DATA_HERE'); }
* </style>
* </pre>
* <p>
* This CSS string escaper processes the following characters:
* <ul>
* <li>
* CSS string characters: <code>' (U+0022)</code>, <code>" (U+0027)</code>,
* <code>\ (U+005C)</code>
* </li>
* <li>
* HTML characters: <code>/ (U+002F)</code>,
* <code>< (U+003C)</code>, <code>> (U+003E)</code>,
* <code>& (U+0026)</code>
* </li>
* <li>
* Control characters: <code>\b (U+0008)</code>,
* <code>\t (U+0009)</code>, <code>\n (U+000A)</code>,
* <code>\f (U+000C)</code>, <code>\r (U+000D)</code>
* </li>
* <li>
* Unicode newlines: <code>LS (U+2028)</code>, <code>PS (U+2029)</code>
* </li>
* </ul>
*
* @param input the string to be escaped
* @return the CSS string escaped or <code>null</code> if <code>input</code> is null
* @since 1.0
*/
public static String cssString(String input) {
if (input == null)
return null;
int length = input.length();
StringBuilder output = allocateStringBuilder(length);
for (int i = 0; i < length; i++) {
char c = input.charAt(i);
switch (c) {
// Control chars
case '\b':
output.append("\\08 ");
break;
case '\t':
output.append("\\09 ");
break;
case '\n':
output.append("\\0A ");
break;
case '\f':
output.append("\\0C ");
break;
case '\r':
output.append("\\0D ");
break;
// String chars
case '\'':
output.append("\\27 ");
break;
case '"':
output.append("\\22 ");
break;
case '\\':
output.append("\\5C ");
break;
// HTML chars for closing the parent context
case '&':
output.append("\\26 ");
break;
case '/':
output.append("\\2F ");
break;
case '<':
output.append("\\3C ");
break;
case '>':
output.append("\\3E ");
break;
// Unicode
case '\u2028':
output.append("\\002028 ");
break;
case '\u2029':
output.append("\\002029 ");
break;
default:
output.append(c);
break;
}
}
return output.toString();
}
SQL LIKE clause escaper.
This SQL LIKE clause escaper does not protect against SQL injection, but ensure
that the string to be consumed in SQL LIKE clause does not alter the current
LIKE query by inserting %
or _
:
entityManager.createQuery("FROM MyEntity e WHERE e.content LIKE :like_query ESCAPE '@'")
.setParameter("like_query", "%" + Escape.sqlLikeClause(USER_DATA_HERE))
.getResultList();
This escaper has to be used with a safe SQL query construct such as the JPQL
named parameterized query in the previous example.
This escaper uses by default the @
as escape character. The other method sqlLikeClause(String, char)
allows for using a different escape character such as \
.
This SQL LIKE escaper processes the following characters:
-
SQL LIKE characters:
_ (U+005F)
, % (U+0025)
,
@ (U+0040)
Params: - input – the string to be escaped
Returns: the SQL LIKE escaped string or null
if input
is null Since: 1.0
/**
* SQL LIKE clause escaper.
* <p>
* This SQL LIKE clause escaper does not protect against SQL injection, but ensure
* that the string to be consumed in SQL LIKE clause does not alter the current
* LIKE query by inserting <code>%</code> or <code>_</code>:
* <pre>
* entityManager.createQuery("FROM MyEntity e WHERE e.content LIKE :like_query ESCAPE '@'")
* .setParameter("like_query", "%" + Escape.sqlLikeClause(USER_DATA_HERE))
* .getResultList();
* </pre>
* This escaper has to be used with a safe SQL query construct such as the JPQL
* named parameterized query in the previous example.
* <p>
* This escaper uses by default the <code>@</code> as escape character. The other method
* {@link #sqlLikeClause(String,char)} allows for using a different escape character such as
* <code>\</code>.
*
* <p>
* This SQL LIKE escaper processes the following characters:
* <ul>
* <li>
* SQL LIKE characters: <code>_ (U+005F)</code>, <code>% (U+0025)</code>,
* <code>@ (U+0040)</code>
* </li>
* </ul>
*
* @param input the string to be escaped
* @return the SQL LIKE escaped string or <code>null</code> if <code>input</code> is null
* @since 1.0
*/
public static String sqlLikeClause(String input) {
return sqlLikeClause(input, '@');
}
SQL LIKE clause escaper.
Similar to sqlLikeClause(String)
, but allows to specify the escape character to be used. When a character different than @
is used, @
will
not be escaped by the escaper, and the specified escape character will be.
Params: - input – the string to be escaped
- escape – the escape character to be used
Returns: the SQL LIKE escaped string or null
if input
is null Since: 1.0
/**
* SQL LIKE clause escaper.
* <p>
* Similar to {@link #sqlLikeClause(String)}, but allows to specify the escape character
* to be used. When a character different than <code>@</code> is used, <code>@</code> will
* not be escaped by the escaper, and the specified escape character will be.
*
* @param input the string to be escaped
* @param escape the escape character to be used
* @return the SQL LIKE escaped string or <code>null</code> if <code>input</code> is null
* @since 1.0
*/
public static String sqlLikeClause(String input, char escape) {
if (input == null)
return null;
int length = input.length();
StringBuilder output = allocateStringBuilder(length);
for (int i = 0; i < length; i++) {
char c = input.charAt(i);
if (c == escape || c == '_' || c == '%') {
output.append(escape);
}
output.append(c);
}
return output.toString();
}
Compute the allocation size of the StringBuilder based on the length.
/**
* Compute the allocation size of the StringBuilder based on the length.
*/
private static StringBuilder allocateStringBuilder(int length) {
// Allocate enough temporary buffer space to avoid reallocation in most
// cases. If you believe you will output large amount of data at once
// you might need to change the factor.
int buflen = length;
if (length * 2 > 0)
buflen = length * 2;
return new StringBuilder(buflen);
}
}