mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Python: Expand azure blob modeling
Now we can differentiate between the classes
This commit is contained in:
@@ -15,35 +15,100 @@ import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import semmle.python.ApiGraphs
|
||||
|
||||
API::Node getClient() {
|
||||
API::Node getBlobServiceClient() {
|
||||
result =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember(["ContainerClient", "BlobClient", "BlobServiceClient"])
|
||||
.getAMember()
|
||||
.getMember("BlobServiceClient")
|
||||
.getReturn()
|
||||
or
|
||||
result =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobServiceClient")
|
||||
.getMember("from_connection_string")
|
||||
.getReturn()
|
||||
}
|
||||
|
||||
API::CallNode getTransitionToContainerClient() {
|
||||
result = getBlobServiceClient().getMember("get_container_client").getACall()
|
||||
or
|
||||
result = getBlobClient().getMember("_get_container_client").getACall()
|
||||
}
|
||||
|
||||
API::Node getContainerClient() {
|
||||
result = getTransitionToContainerClient().getReturn()
|
||||
or
|
||||
result =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("ContainerClient")
|
||||
.getReturn()
|
||||
or
|
||||
result =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("ContainerClient")
|
||||
.getMember(["from_connection_string", "from_container_url"])
|
||||
.getReturn()
|
||||
}
|
||||
|
||||
API::CallNode getTransitionToBlobClient() {
|
||||
result = [getBlobServiceClient(), getContainerClient()].getMember("get_blob_client").getACall()
|
||||
}
|
||||
|
||||
API::Node getBlobClient() {
|
||||
result = getTransitionToBlobClient().getReturn()
|
||||
or
|
||||
result =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobClient")
|
||||
.getReturn()
|
||||
or
|
||||
result =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobClient")
|
||||
.getMember(["from_connection_string", "from_blob_url"])
|
||||
.getReturn()
|
||||
}
|
||||
|
||||
API::Node anyClient() { result in [getBlobServiceClient(), getContainerClient(), getBlobClient()] }
|
||||
|
||||
module AzureBlobClientConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) {
|
||||
exists(DataFlow::AttrWrite attr |
|
||||
node = getClient().getAValueReachableFromSource() and
|
||||
node = anyClient().getAValueReachableFromSource() and
|
||||
attr.accesses(node, ["key_encryption_key", "key_resolver_function"])
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(DataFlow::AttrWrite attr |
|
||||
node = getClient().getAValueReachableFromSource() and
|
||||
node = anyClient().getAValueReachableFromSource() and
|
||||
attr.accesses(node, "encryption_version") and
|
||||
attr.getValue().asExpr().(StrConst).getText() in ["'2.0'", "2.0"]
|
||||
)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
call in [getTransitionToContainerClient(), getTransitionToBlobClient()] and
|
||||
node1 = call.getObject() and
|
||||
node2 = call
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
call = getClient().getMember("upload_blob").getACall() and
|
||||
call = getBlobClient().getMember("upload_blob").getACall() and
|
||||
node = call.getObject()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
edges
|
||||
| test.py:8:5:8:15 | ControlFlowNode for blob_client | test.py:10:9:10:19 | ControlFlowNode for blob_client |
|
||||
| test.py:16:5:16:15 | ControlFlowNode for blob_client | test.py:22:9:22:19 | ControlFlowNode for blob_client |
|
||||
| test.py:38:5:38:15 | ControlFlowNode for blob_client | test.py:39:12:39:22 | ControlFlowNode for blob_client |
|
||||
| test.py:39:12:39:22 | ControlFlowNode for blob_client | test.py:43:10:43:33 | ControlFlowNode for get_unsafe_blob_client() |
|
||||
| test.py:43:10:43:33 | ControlFlowNode for get_unsafe_blob_client() | test.py:45:9:45:10 | ControlFlowNode for bc |
|
||||
| test.py:9:5:9:15 | ControlFlowNode for blob_client | test.py:11:9:11:19 | ControlFlowNode for blob_client |
|
||||
| test.py:17:5:17:23 | ControlFlowNode for blob_service_client | test.py:21:9:21:19 | ControlFlowNode for blob_client |
|
||||
| test.py:27:5:27:20 | ControlFlowNode for container_client | test.py:31:9:31:19 | ControlFlowNode for blob_client |
|
||||
| test.py:37:5:37:15 | ControlFlowNode for blob_client | test.py:43:9:43:19 | ControlFlowNode for blob_client |
|
||||
| test.py:59:5:59:15 | ControlFlowNode for blob_client | test.py:60:12:60:22 | ControlFlowNode for blob_client |
|
||||
| test.py:60:12:60:22 | ControlFlowNode for blob_client | test.py:64:10:64:33 | ControlFlowNode for get_unsafe_blob_client() |
|
||||
| test.py:64:10:64:33 | ControlFlowNode for get_unsafe_blob_client() | test.py:66:9:66:10 | ControlFlowNode for bc |
|
||||
nodes
|
||||
| test.py:8:5:8:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:10:9:10:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:16:5:16:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:22:9:22:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:38:5:38:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:39:12:39:22 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:43:10:43:33 | ControlFlowNode for get_unsafe_blob_client() | semmle.label | ControlFlowNode for get_unsafe_blob_client() |
|
||||
| test.py:45:9:45:10 | ControlFlowNode for bc | semmle.label | ControlFlowNode for bc |
|
||||
| test.py:9:5:9:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:11:9:11:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:17:5:17:23 | ControlFlowNode for blob_service_client | semmle.label | ControlFlowNode for blob_service_client |
|
||||
| test.py:21:9:21:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:27:5:27:20 | ControlFlowNode for container_client | semmle.label | ControlFlowNode for container_client |
|
||||
| test.py:31:9:31:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:37:5:37:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:43:9:43:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:59:5:59:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:60:12:60:22 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:64:10:64:33 | ControlFlowNode for get_unsafe_blob_client() | semmle.label | ControlFlowNode for get_unsafe_blob_client() |
|
||||
| test.py:66:9:66:10 | ControlFlowNode for bc | semmle.label | ControlFlowNode for bc |
|
||||
subpaths
|
||||
#select
|
||||
| test.py:10:9:10:19 | ControlFlowNode for blob_client | test.py:8:5:8:15 | ControlFlowNode for blob_client | test.py:10:9:10:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
|
||||
| test.py:22:9:22:19 | ControlFlowNode for blob_client | test.py:16:5:16:15 | ControlFlowNode for blob_client | test.py:22:9:22:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
|
||||
| test.py:45:9:45:10 | ControlFlowNode for bc | test.py:38:5:38:15 | ControlFlowNode for blob_client | test.py:45:9:45:10 | ControlFlowNode for bc | Unsafe usage of v1 version of Azure Storage client-side encryption |
|
||||
| test.py:11:9:11:19 | ControlFlowNode for blob_client | test.py:9:5:9:15 | ControlFlowNode for blob_client | test.py:11:9:11:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
|
||||
| test.py:21:9:21:19 | ControlFlowNode for blob_client | test.py:17:5:17:23 | ControlFlowNode for blob_service_client | test.py:21:9:21:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
|
||||
| test.py:31:9:31:19 | ControlFlowNode for blob_client | test.py:27:5:27:20 | ControlFlowNode for container_client | test.py:31:9:31:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
|
||||
| test.py:43:9:43:19 | ControlFlowNode for blob_client | test.py:37:5:37:15 | ControlFlowNode for blob_client | test.py:43:9:43:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
|
||||
| test.py:66:9:66:10 | ControlFlowNode for bc | test.py:59:5:59:15 | ControlFlowNode for blob_client | test.py:66:9:66:10 | ControlFlowNode for bc | Unsafe usage of v1 version of Azure Storage client-side encryption |
|
||||
|
||||
@@ -1,17 +1,38 @@
|
||||
from azure.storage.blob import BlobServiceClient
|
||||
from azure.storage.blob import BlobServiceClient, ContainerClient, BlobClient
|
||||
|
||||
BSC = BlobServiceClient.from_connection_string(...)
|
||||
|
||||
def unsafe():
|
||||
# does not set encryption_version to 2.0, default is unsafe
|
||||
blob_client = BlobServiceClient.get_blob_client(...)
|
||||
blob_client = BSC.get_blob_client(...)
|
||||
blob_client.require_encryption = True
|
||||
blob_client.key_encryption_key = ...
|
||||
with open("decryptedcontentfile.txt", "rb") as stream:
|
||||
blob_client.upload_blob(stream) # BAD
|
||||
|
||||
|
||||
def unsafe_setting_on_blob_service_client():
|
||||
blob_service_client = BlobServiceClient.from_connection_string(...)
|
||||
blob_service_client.require_encryption = True
|
||||
blob_service_client.key_encryption_key = ...
|
||||
|
||||
blob_client = blob_service_client.get_blob_client(...)
|
||||
with open("decryptedcontentfile.txt", "rb") as stream:
|
||||
blob_client.upload_blob(stream)
|
||||
|
||||
|
||||
def unsafe_setting_on_container_client():
|
||||
container_client = ContainerClient.from_connection_string(...)
|
||||
container_client.require_encryption = True
|
||||
container_client.key_encryption_key = ...
|
||||
|
||||
blob_client = container_client.get_blob_client(...)
|
||||
with open("decryptedcontentfile.txt", "rb") as stream:
|
||||
blob_client.upload_blob(stream)
|
||||
|
||||
|
||||
def potentially_unsafe(use_new_version=False):
|
||||
blob_client = BlobServiceClient.get_blob_client(...)
|
||||
blob_client = BSC.get_blob_client(...)
|
||||
blob_client.require_encryption = True
|
||||
blob_client.key_encryption_key = ...
|
||||
|
||||
@@ -23,7 +44,7 @@ def potentially_unsafe(use_new_version=False):
|
||||
|
||||
|
||||
def safe():
|
||||
blob_client = BlobServiceClient.get_blob_client(...)
|
||||
blob_client = BSC.get_blob_client(...)
|
||||
blob_client.require_encryption = True
|
||||
blob_client.key_encryption_key = ...
|
||||
# GOOD: Must use `encryption_version` set to `2.0`
|
||||
@@ -33,7 +54,7 @@ def safe():
|
||||
|
||||
|
||||
def get_unsafe_blob_client():
|
||||
blob_client = BlobServiceClient.get_blob_client(...)
|
||||
blob_client = BSC.get_blob_client(...)
|
||||
blob_client.require_encryption = True
|
||||
blob_client.key_encryption_key = ...
|
||||
return blob_client
|
||||
@@ -46,7 +67,7 @@ def unsafe_with_calls():
|
||||
|
||||
|
||||
def get_safe_blob_client():
|
||||
blob_client = BlobServiceClient.get_blob_client(...)
|
||||
blob_client = BSC.get_blob_client(...)
|
||||
blob_client.require_encryption = True
|
||||
blob_client.key_encryption_key = ...
|
||||
blob_client.encryption_version = '2.0'
|
||||
|
||||
Reference in New Issue
Block a user