JavaScript: Add new query PostMessageStar.

This commit is contained in:
Max Schaefer
2019-01-29 09:14:57 +00:00
parent e2f27014b5
commit 769e407c24
12 changed files with 177 additions and 0 deletions

View File

@@ -14,6 +14,7 @@
| **Query** | **Tags** | **Purpose** |
|-----------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Cross-window communication with unrestricted target origin (`js/cross-window-information-leak`) | security, external/cwe/359 | Highlights code that sends potentially sensitive information to another window without restricting the receiver window's origin. Results are shown on LGTM by default. |
| Double escaping or unescaping (`js/double-escaping`) | correctness, security, external/cwe/cwe-116 | Highlights potential double escaping or unescaping of special characters, indicating a possible violation of [CWE-116](https://cwe.mitre.org/data/definitions/116.html). Results are shown on LGTM by default. |
| Incomplete regular expression for hostnames (`js/incomplete-hostname-regexp`) | correctness, security, external/cwe/cwe-020 | Highlights hostname sanitizers that are likely to be incomplete, indicating a violation of [CWE-020](https://cwe.mitre.org/data/definitions/20.html). Results are shown on LGTM by default.|
| Incomplete URL substring sanitization | correctness, security, external/cwe/cwe-020 | Highlights URL sanitizers that are likely to be incomplete, indicating a violation of [CWE-020](https://cwe.mitre.org/data/definitions/20.html). Results shown on LGTM by default. |

View File

@@ -22,6 +22,7 @@
+ semmlecode-javascript-queries/Security/CWE-338/InsecureRandomness.ql: /Security/CWE/CWE-338
+ semmlecode-javascript-queries/Security/CWE-346/CorsMisconfigurationForCredentials.ql: /Security/CWE/CWE-346
+ semmlecode-javascript-queries/Security/CWE-352/MissingCsrfMiddleware.ql: /Security/CWE/CWE-352
+ semmlecode-javascript-queries/Security/CWE-359/PostMessageStar.ql: /Security/CWE/CWE-359
+ semmlecode-javascript-queries/Security/CWE-400/RemotePropertyInjection.ql: /Security/CWE/CWE-400
+ semmlecode-javascript-queries/Security/CWE-502/UnsafeDeserialization.ql: /Security/CWE/CWE-502
+ semmlecode-javascript-queries/Security/CWE-506/HardcodedDataInterpretedAsCode.ql: /Security/CWE/CWE-506

View File

@@ -0,0 +1,56 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
The <code>window.postMessage</code> method allows different windows or iframes
to communicate directly, even if they were loaded from different origins, circumventing
the usual same-origin policy.
</p>
<p>
The sender of the message can restrict the origin of the receiver by specifying
a target origin. If the receiver window does not come from this origin, the
message is not sent.
</p>
<p>
Alternatively, the sender can specify a target origin of <code>'*'</code>, which means
that any origin is acceptable and the message is always sent.
</p>
<p>
This feature should not be used if the message being sent contains sensitive data such
as user credentials: the target window may have been loaded from a malicious site,
to which the data would then become available.
</p>
</overview>
<recommendation>
<p>
If possible, specify a target origin when using <code>window.postMessage</code>.
Alternatively, encrypt the sensitive data before sending it to prevent an unauthorized
receiver from accessing it.
</p>
</recommendation>
<example>
<p>
The following example code sends user credentials (in this case, their user
name) to <code>window.parent</code> without checking its origin. If a malicious site
loads the page containing this code into an iframe it would be able to gain access
to the user name.
</p>
<sample src="examples/PostMessageStar.js"/>
<p>
To prevent this from happening, the origin of the target window should be restricted,
as in this example:
</p>
<sample src="examples/PostMessageStarGood.js"/>
</example>
<references>
<li>Mozilla Developer Network: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage">Window.postMessage</a>.</li>
<li>Mozilla Developer Network: <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy">Same-origin policy</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,22 @@
/**
* @name Cross-window communication with unrestricted target origin
* @description When sending sensitive information to another window using `postMessage`,
* the origin of the target window should be restricted to avoid unintentional
* information leaks.
* @kind path-problem
* @problem.severity error
* @precision high
* @id js/cross-window-information-leak
* @tags security
* external/cwe/cwe-359
*/
import javascript
import semmle.javascript.security.dataflow.PostMessageStar::PostMessageStar
import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink,
"Sensitive data returned from $@ is sent to another window without origin restriction.",
source.getNode(), "here"

View File

@@ -0,0 +1 @@
window.parent.postMessage(userName, '*');

View File

@@ -0,0 +1 @@
window.parent.postMessage(userName, 'https://lgtm.com');

View File

@@ -0,0 +1,84 @@
/**
* Provides a taint tracking configuration for reasoning about cross-window communication
* with unrestricted origin.
*/
import javascript
private import semmle.javascript.security.SensitiveActions
module PostMessageStar {
/**
* A data flow source for cross-window communication with unrestricted origin.
*/
abstract class Source extends DataFlow::Node { }
/**
* A data flow sink for cross-window communication with unrestricted origin.
*/
abstract class Sink extends DataFlow::Node { }
/**
* A sanitizer for cross-window communication with unrestricted origin.
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* A taint tracking configuration for cross-window communication with unrestricted origin.
*
* This configuration identifies flows from `Source`s, which are sources of
* sensitive data, to `Sink`s, which is an abstract class representing all
* the places sensitive data may be transmitted across window boundaries without restricting
* the origin.
*
* Additional sources or sinks can be added either by extending the relevant class, or by subclassing
* this configuration itself, and amending the sources and sinks.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "PostMessageStar" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
}
/**
* A sensitive expression, viewed as a data flow source for cross-window communication
* with unrestricted origin.
*/
class SensitiveExprSource extends Source, DataFlow::ValueNode { override SensitiveExpr astNode; }
/**
* A variable/property access or function call whose name suggests that it may contain credentials,
* viewed as a data flow source for cross-window communication with unrestricted origin.
*/
class CredentialsSource extends Source {
CredentialsSource() {
exists(string name |
name = this.(DataFlow::InvokeNode).getCalleeName() or
name = this.(DataFlow::PropRead).getPropertyName() or
name = this.asExpr().(VarUse).getVariable().getName()
|
name.regexpMatch(HeuristicNames::suspiciousCredentials()) and
not name.regexpMatch(HeuristicNames::nonSuspicious())
)
}
}
/** A call to any function whose name suggests that it encodes or encrypts its arguments. */
class ProtectSanitizer extends Sanitizer { ProtectSanitizer() { this instanceof ProtectCall } }
/**
* An expression sent using `postMessage` without restricting the target window origin.
*/
class PostMessageStarSink extends Sink {
PostMessageStarSink() {
exists(DataFlow::MethodCallNode postMessage |
postMessage.getMethodName() = "postMessage" and
postMessage.getArgument(1).mayHaveStringValue("*") and
this = postMessage.getArgument(0)
)
}
}
}

View File

@@ -0,0 +1,7 @@
nodes
| PostMessageStar2.js:1:27:1:34 | password |
| PostMessageStar.js:1:27:1:34 | userName |
edges
#select
| PostMessageStar2.js:1:27:1:34 | password | PostMessageStar2.js:1:27:1:34 | password | PostMessageStar2.js:1:27:1:34 | password | Sensitive data returned from $@ is sent to another window without origin restriction. | PostMessageStar2.js:1:27:1:34 | password | here |
| PostMessageStar.js:1:27:1:34 | userName | PostMessageStar.js:1:27:1:34 | userName | PostMessageStar.js:1:27:1:34 | userName | Sensitive data returned from $@ is sent to another window without origin restriction. | PostMessageStar.js:1:27:1:34 | userName | here |

View File

@@ -0,0 +1 @@
window.parent.postMessage(userName, '*');

View File

@@ -0,0 +1 @@
Security/CWE-359/PostMessageStar.ql

View File

@@ -0,0 +1 @@
window.parent.postMessage(password, '*');

View File

@@ -0,0 +1 @@
window.parent.postMessage(userName, 'https://lgtm.com');