mirror of
https://github.com/github/codeql.git
synced 2025-12-18 01:33:15 +01:00
Merge branch 'main' into threat-models
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* The `py/cors-misconfiguration-with-credentials` query, which finds insecure CORS middleware configurations.
|
||||
@@ -50,7 +50,10 @@ module TemplateInjection {
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparison with a constant string, considered as a sanitizer-guard.
|
||||
* A comparison with a constant, considered as a sanitizer-guard.
|
||||
*/
|
||||
class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { }
|
||||
class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { }
|
||||
|
||||
/** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */
|
||||
deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,10 @@ module XsltInjection {
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparison with a constant string, considered as a sanitizer-guard.
|
||||
* A comparison with a constant, considered as a sanitizer-guard.
|
||||
*/
|
||||
class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { }
|
||||
class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { }
|
||||
|
||||
/** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */
|
||||
deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
Web browsers, by default, disallow cross-origin resource sharing via direct HTTP requests.
|
||||
Still, to satisfy some needs that arose with the growth of the web, an expedient was created to make exceptions possible.
|
||||
CORS (Cross-origin resource sharing) is a mechanism that allows resources of a web endpoint (let's call it "Peer A")
|
||||
to be accessed from another web page belonging to a different domain ("Peer B").
|
||||
</p>
|
||||
<p>
|
||||
For that to happen, Peer A needs to make available its CORS configuration via special headers on the desired endpoint
|
||||
via the OPTIONS method.
|
||||
</p>
|
||||
<p>
|
||||
This configuration can also allow the inclusion of cookies on the cross-origin request,
|
||||
(i.e. when the <code>Access-Control-Allow-Credentials</code> header is set to true)
|
||||
meaning that Peer B can send a request to Peer A that will include the cookies as if the request was executed by the user.
|
||||
</p>
|
||||
<p>
|
||||
That can have dangerous effects if the origin of Peer B is not restricted correctly.
|
||||
An example of a dangerous scenario is when <code>Access-Control-Allow-Origin</code> header is set to a value obtained from the request made by Peer B
|
||||
(and not correctly validated), or is set to special values such as <code>*</code> or <code>null</code>.
|
||||
The above values can allow any Peer B to send requests to the misconfigured Peer A on behalf of the user.
|
||||
</p>
|
||||
<p>
|
||||
Example scenario:
|
||||
User is client of a bank that has its API misconfigured to accept CORS requests from any domain.
|
||||
When the user loads an evil page, the evil page sends a request to the bank's API to transfer all funds
|
||||
to evil party's account.
|
||||
Given that the user was already logged in to the bank website, and had its session cookies set,
|
||||
the evil party's request succeeds.
|
||||
</p>
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>
|
||||
When configuring CORS that allow credentials passing,
|
||||
it's best not to use user-provided values for the allowed origins response header,
|
||||
especially if the cookies grant session permissions on the user's account.
|
||||
</p>
|
||||
<p>
|
||||
It also can be very dangerous to set the allowed origins to <code>null</code> (which can be bypassed).
|
||||
</p>
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>
|
||||
The first example shows a possible CORS misconfiguration case:
|
||||
</p>
|
||||
<sample src="CorsMisconfigurationMiddlewareBad.py"/>
|
||||
<p>
|
||||
The second example shows a better configuration:
|
||||
</p>
|
||||
<sample src="CorsMisconfigurationMiddlewareGood.py"/>
|
||||
</example>
|
||||
<references>
|
||||
<li>
|
||||
Reference 1: <a href="https://portswigger.net/web-security/cors">PortSwigger Web Security Academy on CORS</a>.
|
||||
</li>
|
||||
<li>
|
||||
Reference 2: <a href="https://www.youtube.com/watch?v=wgkj4ZgxI4c">AppSec EU 2017 Exploiting CORS Misconfigurations For Bitcoins And Bounties by James Kettle</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @name Cors misconfiguration with credentials
|
||||
* @description Disabling or weakening SOP protection may make the application
|
||||
* vulnerable to a CORS attack.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.8
|
||||
* @precision high
|
||||
* @id py/cors-misconfiguration-with-credentials
|
||||
* @tags security
|
||||
* external/cwe/cwe-942
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.Concepts
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
|
||||
predicate containsStar(DataFlow::Node array) {
|
||||
array.asExpr() instanceof List and
|
||||
array.asExpr().getASubExpression().(StringLiteral).getText() in ["*", "null"]
|
||||
or
|
||||
array.asExpr().(StringLiteral).getText() in ["*", "null"]
|
||||
}
|
||||
|
||||
predicate isCorsMiddleware(Http::Server::CorsMiddleware middleware) {
|
||||
middleware.getMiddlewareName() = "CORSMiddleware"
|
||||
}
|
||||
|
||||
predicate credentialsAllowed(Http::Server::CorsMiddleware middleware) {
|
||||
middleware.getCredentialsAllowed().asExpr() instanceof True
|
||||
}
|
||||
|
||||
from Http::Server::CorsMiddleware a
|
||||
where
|
||||
credentialsAllowed(a) and
|
||||
containsStar(a.getOrigins().getALocalSource()) and
|
||||
isCorsMiddleware(a)
|
||||
select a,
|
||||
"This CORS middleware uses a vulnerable configuration that allows arbitrary websites to make authenticated cross-site requests"
|
||||
@@ -0,0 +1,21 @@
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
origins = [
|
||||
"*"
|
||||
]
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=origins,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def main():
|
||||
return {"message": "Hello World"}
|
||||
@@ -0,0 +1,24 @@
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
origins = [
|
||||
"http://localhost.tiangolo.com",
|
||||
"https://localhost.tiangolo.com",
|
||||
"http://localhost",
|
||||
"http://localhost:8080",
|
||||
]
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=origins,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def main():
|
||||
return {"message": "Hello World"}
|
||||
@@ -19,7 +19,7 @@ private module EmailXssConfig implements DataFlow::ConfigSig {
|
||||
predicate isBarrier(DataFlow::Node sanitizer) {
|
||||
sanitizer = any(HtmlEscaping esc).getOutput()
|
||||
or
|
||||
sanitizer instanceof StringConstCompareBarrier
|
||||
sanitizer instanceof ConstCompareBarrier
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
|
||||
@@ -15,7 +15,7 @@ private module CsvInjectionConfig implements DataFlow::ConfigSig {
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node = DataFlow::BarrierGuard<startsWithCheck/3>::getABarrierNode() or
|
||||
node instanceof StringConstCompareBarrier
|
||||
node instanceof ConstCompareBarrier
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user