Skip to content

Commit e43e581

Browse files
New queries to detect unsafe client side encryption in Azure Storage
1 parent e98bdbf commit e43e581

9 files changed

+380
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
var client = new BlobClient(myConnectionString, new SpecializedBlobClientOptions()
3+
{
4+
// BAD: Using an outdated SDK that does not support client side encryption version V2_0
5+
ClientSideEncryption = new ClientSideEncryptionOptions()
6+
{
7+
KeyEncryptionKey = myKey,
8+
KeyResolver = myKeyResolver,
9+
KeyWrapAlgorihm = myKeyWrapAlgorithm
10+
}
11+
});
12+
13+
var client = new BlobClient(myConnectionString, new SpecializedBlobClientOptions()
14+
{
15+
// BAD: Using the outdated client side encryption version V1_0
16+
ClientSideEncryption = new ClientSideEncryptionOptions(ClientSideEncryptionVersion.V1_0)
17+
{
18+
KeyEncryptionKey = myKey,
19+
KeyResolver = myKeyResolver,
20+
KeyWrapAlgorihm = myKeyWrapAlgorithm
21+
}
22+
});
23+
24+
var client = new BlobClient(myConnectionString, new SpecializedBlobClientOptions()
25+
{
26+
// GOOD: Using client side encryption version V2_0
27+
ClientSideEncryption = new ClientSideEncryptionOptions(ClientSideEncryptionVersion.V2_0)
28+
{
29+
KeyEncryptionKey = myKey,
30+
KeyResolver = myKeyResolver,
31+
KeyWrapAlgorihm = myKeyWrapAlgorithm
32+
}
33+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
2+
<qhelp>
3+
4+
5+
<overview>
6+
<p>Azure Storage .NET, Java, and Python SDKs support encryption on the client with a customer-managed key that is maintained in Azure Key Vault or another key store.</p>
7+
<p>Current release versions of the Azure Storage SDKs use cipher block chaining (CBC mode) for client-side encryption (referred to as <code>v1</code>).</p>
8+
9+
</overview>
10+
<recommendation>
11+
12+
<p>Consider switching to <code>v1</code> client-side encryption.</p>
13+
14+
</recommendation>
15+
<example>
16+
17+
<p>The following example shows an HTTP request parameter being used directly in a forming a
18+
new request without validating the input, which facilitates SSRF attacks.
19+
It also shows how to remedy the problem by validating the user input against a known fixed string.
20+
</p>
21+
22+
<sample src="UnsafeUsageOfClientSideEncryptionVersion.cs" />
23+
24+
</example>
25+
<references>
26+
<li>
27+
<a href="http://aka.ms/azstorageclientencryptionblog">Azure Storage Client Encryption Blog.</a>
28+
</li>
29+
30+
</references>
31+
</qhelp>
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* @name Unsafe usage of v1 version of Azure Storage client-side encryption (CVE-2022-PENDING).
3+
* @description Unsafe usage of v1 version of Azure Storage client-side encryption, please refer to http://aka.ms/azstorageclientencryptionblog
4+
* @kind problem
5+
* @tags security
6+
* cryptography
7+
* external/cwe/cwe-327
8+
* @id cs/azure-storage/unsafe-usage-of-client-side-encryption-version
9+
* @problem.severity error
10+
* @precision high
11+
*/
12+
13+
import csharp
14+
15+
/**
16+
* Holds if `oc` is creating an object of type `c` = `Azure.Storage.ClientSideEncryptionOptions`
17+
* and `e` is the `version` argument to the contructor
18+
*/
19+
predicate isCreatingAzureClientSideEncryptionObject(ObjectCreation oc, Class c, Expr e) {
20+
exists(Parameter p | p.hasName("version") |
21+
c.getQualifiedName() in ["Azure.Storage.ClientSideEncryptionOptions"] and
22+
oc.getTarget() = c.getAConstructor() and
23+
e = oc.getArgumentForParameter(p)
24+
)
25+
}
26+
27+
/**
28+
* Holds if `oc` is an object creation of the outdated type `c` = `Microsoft.Azure.Storage.Blob.BlobEncryptionPolicy`
29+
*/
30+
predicate isCreatingOutdatedAzureClientSideEncryptionObject(ObjectCreation oc, Class c) {
31+
c.getQualifiedName() in ["Microsoft.Azure.Storage.Blob.BlobEncryptionPolicy"] and
32+
oc.getTarget() = c.getAConstructor()
33+
}
34+
35+
/**
36+
* Holds if the Azure.Storage assembly for `c` is a version knwon to support
37+
* version 2+ for client-side encryption and if the argument for the constructor `version`
38+
* is set to a secure value.
39+
*/
40+
predicate isObjectCreationSafe(Class c, Expr versionExpr, Assembly asm) {
41+
// Check if the Azure.Storage assembly version has the fix
42+
exists(int versionCompare |
43+
versionCompare = asm.getVersion().compareTo("12.12.0.0") and
44+
versionCompare >= 0
45+
) and
46+
// and that the version argument for the constructor is guaranteed to be Version2
47+
isExprAnAccessToSafeClientSideEncryptionVersionValue(versionExpr)
48+
}
49+
50+
/**
51+
* Holds if the expression `e` is an access to a safe version of the enum `ClientSideEncryptionVersion`
52+
* or an equivalent numeric value
53+
*/
54+
predicate isExprAnAccessToSafeClientSideEncryptionVersionValue(Expr e) {
55+
exists(EnumConstant ec |
56+
ec.hasQualifiedName("Azure.Storage.ClientSideEncryptionVersion.V2_0") and
57+
ec.getAnAccess() = e
58+
)
59+
or
60+
e.getValue().toInt() >= 2
61+
}
62+
63+
from Expr e, Class c, Assembly asm
64+
where
65+
asm = c.getLocation() and
66+
(
67+
exists(Expr e2 |
68+
isCreatingAzureClientSideEncryptionObject(e, c, e2) and
69+
not isObjectCreationSafe(c, e2, asm)
70+
)
71+
or
72+
isCreatingOutdatedAzureClientSideEncryptionObject(e, c)
73+
)
74+
select e,
75+
"Unsafe usage of v1 version of Azure Storage client-side encryption (CVE-2022-PENDING). See http://aka.ms/azstorageclientencryptionblog"
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
// BAD: Using an outdated SDK that does not support client side encryption version V2_0
3+
new EncryptedBlobClientBuilder()
4+
.blobClient(blobClient)
5+
.key(resolver.buildAsyncKeyEncryptionKey(keyid).block(), keyWrapAlgorithm)
6+
.buildEncryptedBlobClient()
7+
.uploadWithResponse(new BlobParallelUploadOptions(data)
8+
.setMetadata(metadata)
9+
.setHeaders(headers)
10+
.setTags(tags)
11+
.setTier(tier)
12+
.setRequestConditions(requestConditions)
13+
.setComputeMd5(computeMd5)
14+
.setParallelTransferOptions(parallelTransferOptions),
15+
timeout, context);
16+
17+
// BAD: Using the deprecatedd client side encryption version V1_0
18+
new EncryptedBlobClientBuilder(EncryptionVersion.V1)
19+
.blobClient(blobClient)
20+
.key(resolver.buildAsyncKeyEncryptionKey(keyid).block(), keyWrapAlgorithm)
21+
.buildEncryptedBlobClient()
22+
.uploadWithResponse(new BlobParallelUploadOptions(data)
23+
.setMetadata(metadata)
24+
.setHeaders(headers)
25+
.setTags(tags)
26+
.setTier(tier)
27+
.setRequestConditions(requestConditions)
28+
.setComputeMd5(computeMd5)
29+
.setParallelTransferOptions(parallelTransferOptions),
30+
timeout, context);
31+
32+
33+
// GOOD: Using client side encryption version V2_0
34+
new EncryptedBlobClientBuilder(EncryptionVersion.V2)
35+
.blobClient(blobClient)
36+
.key(resolver.buildAsyncKeyEncryptionKey(keyid).block(), keyWrapAlgorithm)
37+
.buildEncryptedBlobClient()
38+
.uploadWithResponse(new BlobParallelUploadOptions(data)
39+
.setMetadata(metadata)
40+
.setHeaders(headers)
41+
.setTags(tags)
42+
.setTier(tier)
43+
.setRequestConditions(requestConditions)
44+
.setComputeMd5(computeMd5)
45+
.setParallelTransferOptions(parallelTransferOptions),
46+
timeout, context);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
2+
<qhelp>
3+
4+
5+
<overview>
6+
<p>Azure Storage .NET, Java, and Python SDKs support encryption on the client with a customer-managed key that is maintained in Azure Key Vault or another key store.</p>
7+
<p>Current release versions of the Azure Storage SDKs use cipher block chaining (CBC mode) for client-side encryption (referred to as <code>v1</code>).</p>
8+
9+
</overview>
10+
<recommendation>
11+
12+
<p>Consider switching to <code>v1</code> client-side encryption.</p>
13+
14+
</recommendation>
15+
<example>
16+
17+
<p>The following example shows an HTTP request parameter being used directly in a forming a
18+
new request without validating the input, which facilitates SSRF attacks.
19+
It also shows how to remedy the problem by validating the user input against a known fixed string.
20+
</p>
21+
22+
<sample src="UnsafeUsageOfClientSideEncryptionVersion.java" />
23+
24+
</example>
25+
<references>
26+
<li>
27+
<a href="http://aka.ms/azstorageclientencryptionblog">Azure Storage Client Encryption Blog.</a>
28+
</li>
29+
30+
</references>
31+
</qhelp>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/**
2+
* @name Unsafe usage of v1 version of Azure Storage client-side encryption (CVE-2022-PENDING).
3+
* @description Unsafe usage of v1 version of Azure Storage client-side encryption, please refer to http://aka.ms/azstorageclientencryptionblog
4+
* @kind problem
5+
* @tags security
6+
* cryptography
7+
* external/cwe/cwe-327
8+
* @id java/azure-storage/unsafe-client-side-encryption-in-use
9+
* @problem.severity error
10+
* @precision high
11+
*/
12+
13+
import java
14+
15+
/**
16+
* Holds if the call `call` is an object creation for a class `EncryptedBlobClientBuilder`
17+
* that takes no arguments, which means that it is using V1 encryption
18+
*/
19+
predicate isCreatingOutdatedAzureClientSideEncryptionObject(Call call, Class c) {
20+
exists(string package, string type, Constructor constructor |
21+
c.hasQualifiedName(package, type) and
22+
c.getAConstructor() = constructor and
23+
call.getCallee() = constructor and
24+
(
25+
type = "EncryptedBlobClientBuilder" and
26+
package = "com.azure.storage.blob.specialized.cryptography" and
27+
not exists(Expr e | e = call.getArgument(0))
28+
or
29+
type = "BlobEncryptionPolicy" and package = "com.microsoft.azure.storage.blob"
30+
)
31+
)
32+
}
33+
34+
/**
35+
* Holds if the call `call` is an object creation for a class `EncryptedBlobClientBuilder`
36+
* that takes `versionArg` as the argument for the version.
37+
*/
38+
predicate isCreatingAzureClientSideEncryptionObjectNewVersion(Call call, Class c, Expr versionArg) {
39+
exists(string package, string type, Constructor constructor |
40+
c.hasQualifiedName(package, type) and
41+
c.getAConstructor() = constructor and
42+
call.getCallee() = constructor and
43+
type = "EncryptedBlobClientBuilder" and
44+
package = "com.azure.storage.blob.specialized.cryptography" and
45+
versionArg = call.getArgument(0)
46+
)
47+
}
48+
49+
/**
50+
* Holds if the call `call` is an object creation for a class `EncryptedBlobClientBuilder`
51+
* that takes `versionArg` as the argument for the version, and the version number is safe
52+
*/
53+
predicate isCreatingSafeAzureClientSideEncryptionObject(Call call, Class c, Expr versionArg) {
54+
isCreatingAzureClientSideEncryptionObjectNewVersion(call, c, versionArg) and
55+
exists(FieldRead fr, Field f |
56+
fr = versionArg and
57+
f.getAnAccess() = fr and
58+
f.hasQualifiedName("com.azure.storage.blob.specialized.cryptography", "EncryptionVersion", "V2")
59+
)
60+
}
61+
62+
from Expr e, Class c
63+
where
64+
exists(Expr argVersion |
65+
isCreatingAzureClientSideEncryptionObjectNewVersion(e, c, argVersion) and
66+
not isCreatingSafeAzureClientSideEncryptionObject(e, c, argVersion)
67+
)
68+
or
69+
isCreatingOutdatedAzureClientSideEncryptionObject(e, c)
70+
select e,
71+
"Unsafe usage of v1 version of Azure Storage client-side encryption (CVE-2022-PENDING). See http://aka.ms/azstorageclientencryptionblog"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob_name)
2+
blob_client.require_encryption = True
3+
blob_client.key_encryption_key = kek
4+
# GOOD: Must use `encryption_version` set to `2.0`
5+
blob_client.encryption_version = '2.0' # Use Version 2.0!
6+
with open(“decryptedcontentfile.txt”, “rb”) as stream:
7+
blob_client.upload_blob(stream, overwrite=OVERWRITE_EXISTING)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
2+
<qhelp>
3+
4+
5+
<overview>
6+
<p>Azure Storage .NET, Java, and Python SDKs support encryption on the client with a customer-managed key that is maintained in Azure Key Vault or another key store.</p>
7+
<p>Current release versions of the Azure Storage SDKs use cipher block chaining (CBC mode) for client-side encryption (referred to as <code>v1</code>).</p>
8+
9+
</overview>
10+
<recommendation>
11+
12+
<p>Consider switching to <code>v1</code> client-side encryption.</p>
13+
14+
</recommendation>
15+
<example>
16+
17+
<p>The following example shows an HTTP request parameter being used directly in a forming a
18+
new request without validating the input, which facilitates SSRF attacks.
19+
It also shows how to remedy the problem by validating the user input against a known fixed string.
20+
</p>
21+
22+
<sample src="UnsafeUsageOfClientSideEncryptionVersion.py" />
23+
24+
</example>
25+
<references>
26+
<li>
27+
<a href="http://aka.ms/azstorageclientencryptionblog">Azure Storage Client Encryption Blog.</a>
28+
</li>
29+
30+
</references>
31+
</qhelp>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @name Unsafe usage of v1 version of Azure Storage client-side encryption (CVE-2022-PENDING).
3+
* @description Unsafe usage of v1 version of Azure Storage client-side encryption, please refer to http://aka.ms/azstorageclientencryptionblog
4+
* @kind problem
5+
* @tags security
6+
* cryptography
7+
* external/cwe/cwe-327
8+
* @id python/azure-storage/unsafe-client-side-encryption-in-use
9+
* @problem.severity error
10+
* @precision medium
11+
*/
12+
13+
import python
14+
15+
predicate isUnsafeClientSideAzureStorageEncryptionViaAttributes(Call call, AttrNode node) {
16+
exists(ControlFlowNode ctrlFlowNode, AssignStmt astmt, Attribute a |
17+
astmt.getATarget() = a and
18+
a.getAttr() in ["key_encryption_key", "key_resolver_function"] and
19+
a.getAFlowNode() = node and
20+
node.strictlyReaches(ctrlFlowNode) and
21+
node != ctrlFlowNode and
22+
call.getAChildNode().(Attribute).getAttr() = "upload_blob" and
23+
ctrlFlowNode = call.getAFlowNode() and
24+
not astmt.getValue() instanceof None and
25+
not exists(AssignStmt astmt2, Attribute a2, AttrNode encryptionVersionSet, StrConst uc |
26+
uc = astmt2.getValue() and
27+
uc.getLiteralValue().toString() in ["'2.0'", "2.0"] and
28+
a2.getAttr() = "encryption_version" and
29+
a2.getAFlowNode() = encryptionVersionSet and
30+
encryptionVersionSet.strictlyReaches(ctrlFlowNode)
31+
)
32+
)
33+
}
34+
35+
predicate isUnsafeClientSideAzureStorageEncryptionViaObjectCreation(Call call, ControlFlowNode node) {
36+
exists(Keyword k | k.getAFlowNode() = node |
37+
call.getFunc().(Name).getId().toString() in [
38+
"ContainerClient", "BlobClient", "BlobServiceClient"
39+
] and
40+
k.getArg() = "key_encryption_key" and
41+
k = call.getANamedArg() and
42+
not k.getValue() instanceof None and
43+
not exists(Keyword k2 | k2 = call.getANamedArg() |
44+
k2.getArg() = "encryption_version" and
45+
k2.getValue().(StrConst).getLiteralValue().toString() in ["'2.0'", "2.0"]
46+
)
47+
)
48+
}
49+
50+
from Call call, ControlFlowNode node
51+
where
52+
isUnsafeClientSideAzureStorageEncryptionViaAttributes(call, node) or
53+
isUnsafeClientSideAzureStorageEncryptionViaObjectCreation(call, node)
54+
select node,
55+
"Unsafe usage of v1 version of Azure Storage client-side encryption (CVE-2022-PENDING). See http://aka.ms/azstorageclientencryptionblog"

0 commit comments

Comments
 (0)