mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
JavaScript: Add new query PostMessageStar.
This commit is contained in:
@@ -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. |
|
||||
|
||||
@@ -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
|
||||
|
||||
56
javascript/ql/src/Security/CWE-359/PostMessageStar.qhelp
Normal file
56
javascript/ql/src/Security/CWE-359/PostMessageStar.qhelp
Normal 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>
|
||||
22
javascript/ql/src/Security/CWE-359/PostMessageStar.ql
Normal file
22
javascript/ql/src/Security/CWE-359/PostMessageStar.ql
Normal 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"
|
||||
@@ -0,0 +1 @@
|
||||
window.parent.postMessage(userName, '*');
|
||||
@@ -0,0 +1 @@
|
||||
window.parent.postMessage(userName, 'https://lgtm.com');
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 |
|
||||
@@ -0,0 +1 @@
|
||||
window.parent.postMessage(userName, '*');
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-359/PostMessageStar.ql
|
||||
@@ -0,0 +1 @@
|
||||
window.parent.postMessage(password, '*');
|
||||
@@ -0,0 +1 @@
|
||||
window.parent.postMessage(userName, 'https://lgtm.com');
|
||||
Reference in New Issue
Block a user