зеркало из https://github.com/github/codeql.git
Merge pull request #3892 from asger-semmle/js/redirect-starts-with-sanitizer
Approved by esbena
This commit is contained in:
Коммит
fe0c5a9ea6
|
@ -50,5 +50,9 @@ module ClientSideUrlRedirect {
|
|||
g instanceof DocumentUrl and
|
||||
succ.(DataFlow::PropRead).accesses(pred, "href")
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
guard instanceof HostnameSanitizerGuard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import javascript
|
||||
import semmle.javascript.security.dataflow.RemoteFlowSources
|
||||
import UrlConcatenation
|
||||
private import UrlConcatenation
|
||||
|
||||
module ClientSideUrlRedirect {
|
||||
private import Xss::DomBasedXss as DomBasedXss
|
||||
|
|
|
@ -34,7 +34,8 @@ module ServerSideUrlRedirect {
|
|||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
guard instanceof LocalUrlSanitizingGuard
|
||||
guard instanceof LocalUrlSanitizingGuard or
|
||||
guard instanceof HostnameSanitizerGuard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import javascript
|
||||
import RemoteFlowSources
|
||||
import UrlConcatenation
|
||||
private import UrlConcatenation
|
||||
|
||||
module ServerSideUrlRedirect {
|
||||
/**
|
||||
|
|
|
@ -96,3 +96,15 @@ predicate hostnameSanitizingPrefixEdge(DataFlow::Node source, DataFlow::Node sin
|
|||
hasHostnameSanitizingSubstring(StringConcatenation::getOperand(operator, [0 .. n - 1]))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A check that sanitizes the hostname of a URL.
|
||||
*/
|
||||
class HostnameSanitizerGuard extends TaintTracking::SanitizerGuardNode, StringOps::StartsWith {
|
||||
HostnameSanitizerGuard() { hasHostnameSanitizingSubstring(getSubstring()) }
|
||||
|
||||
override predicate sanitizes(boolean outcome, Expr e) {
|
||||
outcome = getPolarity() and
|
||||
e = getBaseString().asExpr()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,23 @@
|
|||
nodes
|
||||
| sanitizer.js:2:9:2:25 | url |
|
||||
| sanitizer.js:2:15:2:25 | window.name |
|
||||
| sanitizer.js:2:15:2:25 | window.name |
|
||||
| sanitizer.js:4:27:4:29 | url |
|
||||
| sanitizer.js:4:27:4:29 | url |
|
||||
| sanitizer.js:16:27:16:29 | url |
|
||||
| sanitizer.js:16:27:16:29 | url |
|
||||
| sanitizer.js:19:27:19:29 | url |
|
||||
| sanitizer.js:19:27:19:29 | url |
|
||||
| sanitizer.js:22:27:22:29 | url |
|
||||
| sanitizer.js:22:27:22:29 | url |
|
||||
| sanitizer.js:25:27:25:29 | url |
|
||||
| sanitizer.js:25:27:25:29 | url |
|
||||
| sanitizer.js:28:27:28:29 | url |
|
||||
| sanitizer.js:28:27:28:29 | url |
|
||||
| sanitizer.js:31:27:31:29 | url |
|
||||
| sanitizer.js:31:27:31:29 | url |
|
||||
| sanitizer.js:37:27:37:29 | url |
|
||||
| sanitizer.js:37:27:37:29 | url |
|
||||
| tst2.js:2:7:2:33 | href |
|
||||
| tst2.js:2:7:2:33 | href |
|
||||
| tst2.js:2:14:2:28 | window.location |
|
||||
|
@ -80,6 +99,24 @@ nodes
|
|||
| tst.js:6:34:6:50 | document.location |
|
||||
| tst.js:6:34:6:55 | documen ... on.href |
|
||||
edges
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:4:27:4:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:4:27:4:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:16:27:16:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:16:27:16:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:19:27:19:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:19:27:19:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:22:27:22:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:22:27:22:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:25:27:25:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:25:27:25:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:28:27:28:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:28:27:28:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:31:27:31:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:31:27:31:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:37:27:37:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:37:27:37:29 | url |
|
||||
| sanitizer.js:2:15:2:25 | window.name | sanitizer.js:2:9:2:25 | url |
|
||||
| sanitizer.js:2:15:2:25 | window.name | sanitizer.js:2:9:2:25 | url |
|
||||
| tst2.js:2:7:2:33 | href | tst2.js:4:21:4:24 | href |
|
||||
| tst2.js:2:7:2:33 | href | tst2.js:4:21:4:24 | href |
|
||||
| tst2.js:2:14:2:28 | window.location | tst2.js:2:14:2:33 | window.location.href |
|
||||
|
@ -155,6 +192,14 @@ edges
|
|||
| tst.js:6:34:6:50 | document.location | tst.js:6:34:6:55 | documen ... on.href |
|
||||
| tst.js:6:34:6:55 | documen ... on.href | tst.js:6:20:6:56 | indirec ... n.href) |
|
||||
#select
|
||||
| sanitizer.js:4:27:4:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:4:27:4:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
|
||||
| sanitizer.js:16:27:16:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:16:27:16:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
|
||||
| sanitizer.js:19:27:19:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:19:27:19:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
|
||||
| sanitizer.js:22:27:22:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:22:27:22:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
|
||||
| sanitizer.js:25:27:25:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:25:27:25:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
|
||||
| sanitizer.js:28:27:28:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:28:27:28:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
|
||||
| sanitizer.js:31:27:31:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:31:27:31:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
|
||||
| sanitizer.js:37:27:37:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:37:27:37:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
|
||||
| tst2.js:4:21:4:55 | href.su ... '?')+1) | tst2.js:2:14:2:28 | window.location | tst2.js:4:21:4:55 | href.su ... '?')+1) | Untrusted URL redirection due to $@. | tst2.js:2:14:2:28 | window.location | user-provided value |
|
||||
| tst6.js:4:21:4:28 | redirect | tst6.js:2:18:2:45 | $locati ... irect') | tst6.js:4:21:4:28 | redirect | Untrusted URL redirection due to $@. | tst6.js:2:18:2:45 | $locati ... irect') | user-provided value |
|
||||
| tst6.js:6:17:6:24 | redirect | tst6.js:2:18:2:45 | $locati ... irect') | tst6.js:6:17:6:24 | redirect | Untrusted URL redirection due to $@. | tst6.js:2:18:2:45 | $locati ... irect') | user-provided value |
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
function f() {
|
||||
let url = window.name;
|
||||
if (url.startsWith('https://example.com')) {
|
||||
window.location = url; // NOT OK - can be example.com.evil.com
|
||||
}
|
||||
if (url.startsWith('https://example.com/')) {
|
||||
window.location = url; // OK
|
||||
}
|
||||
if (url.startsWith('https://example.com//')) {
|
||||
window.location = url; // OK
|
||||
}
|
||||
if (url.startsWith('https://example.com/foo')) {
|
||||
window.location = url; // OK
|
||||
}
|
||||
if (url.startsWith('https://')) {
|
||||
window.location = url; // NOT OK - does not restrict hostname
|
||||
}
|
||||
if (url.startsWith('https:/')) {
|
||||
window.location = url; // NOT OK - does not restrict hostname
|
||||
}
|
||||
if (url.startsWith('https:')) {
|
||||
window.location = url; // NOT OK - does not restrict hostname
|
||||
}
|
||||
if (url.startsWith('/')) {
|
||||
window.location = url; // NOT OK - can be //evil.com
|
||||
}
|
||||
if (url.startsWith('//')) {
|
||||
window.location = url; // NOT OK - can be //evil.com
|
||||
}
|
||||
if (url.startsWith('//example.com')) {
|
||||
window.location = url; // NOT OK - can be //example.com.evil.com
|
||||
}
|
||||
if (url.startsWith('//example.com/')) {
|
||||
window.location = url; // OK
|
||||
}
|
||||
if (url.endsWith('https://example.com/')) {
|
||||
window.location = url; // NOT OK - could be evil.com?x=https://example.com/
|
||||
}
|
||||
let basedir = whatever() ? 'foo' : 'bar';
|
||||
if (url.startsWith('https://example.com/' + basedir)) {
|
||||
window.location = url; // OK - the whole prefix is not known, but enough to restrict hostname
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче