Merge pull request #2643 from esbena/js/unsafe-jquery

JS: add query js/unsafe-jquery-plugin
This commit is contained in:
Esben Sparre Andreasen
2020-02-18 09:26:14 +01:00
committed by GitHub
12 changed files with 903 additions and 1 deletions

View File

@@ -0,0 +1,101 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Library plugins, such as those for the jQuery library, are often
configurable through options provided by the clients of the
plugin.
Clients, however, do not know the implementation details
of the plugin, so it is important to document the capabilities of each
option. The documentation for the plugin options that the client is
responsible for sanitizing is of particular importance.
Otherwise, the plugin may write user input (for example, a URL query
parameter) to a web page without properly sanitizing it first,
which allows for a cross-site scripting vulnerability in the client
application through dynamic HTML construction.
</p>
</overview>
<recommendation>
<p>
Document all options that can lead to cross-site scripting
attacks, and guard against unsafe inputs where dynamic HTML
construction is not intended.
</p>
</recommendation>
<example>
<p>
The following example shows a jQuery plugin that selects a
DOM element, and copies its text content to another DOM element. The
selection is performed by using the plugin option
<code>sourceSelector</code> as a CSS selector.
</p>
<sample src="examples/UnsafeJQueryPlugin.js" />
<p>
This is, however, not a safe plugin, since the call to
<code>jQuery</code> interprets <code>sourceSelector</code> as HTML if
it is a string that starts with <code>&lt;</code>.
</p>
<p>
Instead of documenting that the client is responsible for
sanitizing <code>sourceSelector</code>, the plugin can use
<code>jQuery.find</code> to always interpret
<code>sourceSelector</code> as a CSS selector:
</p>
<sample src="examples/UnsafeJQueryPlugin_safe.js" />
</example>
<references>
<li>
OWASP:
<a href="https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet">DOM based
XSS Prevention Cheat Sheet</a>.
</li>
<li>
OWASP:
<a href="https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet">XSS
(Cross Site Scripting) Prevention Cheat Sheet</a>.
</li>
<li>
OWASP
<a href="https://www.owasp.org/index.php/DOM_Based_XSS">DOM Based XSS</a>.
</li>
<li>
OWASP
<a href="https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting">Types of Cross-Site
Scripting</a>.
</li>
<li>
Wikipedia: <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">Cross-site scripting</a>.
</li>
<li>
jQuery: <a href="https://learn.jquery.com/plugins/basic-plugin-creation/">Plugin creation</a>.
</li>
<li>
Bootstrap: <a href="https://github.com/twbs/bootstrap/pull/27047">XSS vulnerable bootstrap plugins</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,25 @@
/**
* @name Unsafe jQuery plugin
* @description A jQuery plugin that unintentionally constructs HTML from some of its options may be unsafe to use for clients.
* @kind path-problem
* @problem.severity warning
* @precision high
* @id js/unsafe-jquery-plugin
* @tags security
* external/cwe/cwe-079
* external/cwe/cwe-116
* frameworks/jquery
*/
import javascript
import semmle.javascript.security.dataflow.UnsafeJQueryPlugin::UnsafeJQueryPlugin
import DataFlow::PathGraph
from
Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, JQueryPluginMethod plugin
where
cfg.hasFlowPath(source, sink) and
source.getNode().(Source).getPlugin() = plugin and
not isLikelyIntentionalHtmlSink(plugin, sink.getNode())
select sink.getNode(), source, sink, "Potential XSS vulnerability in the $@.", plugin,
"'$.fn." + plugin.getPluginName() + "' plugin"

View File

@@ -0,0 +1,6 @@
jQuery.fn.copyText = function(options) {
// BAD may evaluate `options.sourceSelector` as HTML
var source = jQuery(options.sourceSelector),
text = source.text();
jQuery(this).text(text);
}

View File

@@ -0,0 +1,6 @@
jQuery.fn.copyText = function(options) {
// GOOD may not evaluate `options.sourceSelector` as HTML
var source = jQuery.find(options.sourceSelector),
text = source.text();
jQuery(this).text(text);
}