always require integrity checking for certain CDNs

This commit is contained in:
Stephan Brandauer
2022-02-15 13:10:14 +01:00
parent 83764df4f5
commit 780fa97869
2 changed files with 29 additions and 7 deletions

View File

@@ -22,15 +22,27 @@ predicate isLocalhostPrefix(string host) {
])
}
bindingset[path]
predicate isUntrustedSourcePath(string path) {
path.substring(0, 2) = "//"
/** A path that is vulnerable to a MITM attack. */
bindingset[url]
predicate isUntrustedSourceUrl(string url) {
url.substring(0, 2) = "//"
or
exists(string hostPath | hostPath = path.regexpCapture("http://(.*)", 1) |
exists(string hostPath | hostPath = url.regexpCapture("http://(.*)", 1) |
not isLocalhostPrefix(hostPath)
)
}
/** A path that needs an integrity check — even with https. */
bindingset[url]
predicate isCdnUrlWithCheckingRequired(string url) {
// Some CDN URLs are required to have an integrity attribute. We only add CDNs to that list
// that recommend integrity-checking.
url.regexpMatch([
"^https?://code\\.jquery\\.com/.*\\.js$", "^https?://cdnjs\\.cloudflare\\.com/.*\\.js$",
"^https?://cdnjs\\.com/.*\\.js$"
])
}
abstract class IncludesUntrustedContent extends HTML::Element {
/** Gets an explanation why this source is untrusted. */
abstract string getProblem();
@@ -39,8 +51,12 @@ abstract class IncludesUntrustedContent extends HTML::Element {
/** A script element that refers to untrusted content. */
class ScriptElementWithUntrustedContent extends IncludesUntrustedContent, HTML::ScriptElement {
ScriptElementWithUntrustedContent() {
isUntrustedSourcePath(this.getSourcePath()) and
not exists(string digest | not digest = "" | this.getIntegrityDigest() = digest)
not exists(string digest | not digest = "" | this.getIntegrityDigest() = digest) and
(
isUntrustedSourceUrl(this.getSourcePath())
or
isCdnUrlWithCheckingRequired(this.getSourcePath())
)
}
override string getProblem() {
@@ -50,7 +66,7 @@ class ScriptElementWithUntrustedContent extends IncludesUntrustedContent, HTML::
/** An iframe element that includes untrusted content. */
class IframeElementWithUntrustedContent extends HTML::IframeElement, IncludesUntrustedContent {
IframeElementWithUntrustedContent() { isUntrustedSourcePath(this.getSourcePath()) }
IframeElementWithUntrustedContent() { isUntrustedSourceUrl(this.getSourcePath()) }
override string getProblem() { result = "iframe elements should use an HTTPS url" }
}