Skip to content

Commit d444359

Browse files
authored
Merge pull request #9776 from raulgarciamsft/azure-sdk-client-encryption-version
New queries to detect unsafe client side encryption in Azure Storage
2 parents d50816a + 6b17890 commit d444359

9 files changed

+447
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
{
3+
SymmetricKey aesKey = new SymmetricKey(kid: "symencryptionkey");
4+
5+
// BAD: Using the outdated client side encryption version V1_0
6+
BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(key: aesKey, keyResolver: null);
7+
BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };
8+
9+
MemoryStream stream = new MemoryStream(buffer);
10+
blob.UploadFromStream(stream, length: size, accessCondition: null, options: uploadOptions);
11+
}
12+
13+
var client = new BlobClient(myConnectionString, new SpecializedBlobClientOptions()
14+
{
15+
// BAD: Using an outdated SDK that does not support client side encryption version V2_0
16+
ClientSideEncryption = new ClientSideEncryptionOptions()
17+
{
18+
KeyEncryptionKey = myKey,
19+
KeyResolver = myKeyResolver,
20+
KeyWrapAlgorihm = myKeyWrapAlgorithm
21+
}
22+
});
23+
24+
var client = new BlobClient(myConnectionString, new SpecializedBlobClientOptions()
25+
{
26+
// BAD: Using the outdated client side encryption version V1_0
27+
ClientSideEncryption = new ClientSideEncryptionOptions(ClientSideEncryptionVersion.V1_0)
28+
{
29+
KeyEncryptionKey = myKey,
30+
KeyResolver = myKeyResolver,
31+
KeyWrapAlgorihm = myKeyWrapAlgorithm
32+
}
33+
});
34+
35+
var client = new BlobClient(myConnectionString, new SpecializedBlobClientOptions()
36+
{
37+
// GOOD: Using client side encryption version V2_0
38+
ClientSideEncryption = new ClientSideEncryptionOptions(ClientSideEncryptionVersion.V2_0)
39+
{
40+
KeyEncryptionKey = myKey,
41+
KeyResolver = myKeyResolver,
42+
KeyWrapAlgorihm = myKeyWrapAlgorithm
43+
}
44+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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>v2</code> client-side encryption.</p>
13+
14+
</recommendation>
15+
<example>
16+
17+
<sample src="UnsafeUsageOfClientSideEncryptionVersion.cs" />
18+
19+
</example>
20+
<references>
21+
<li>
22+
<a href="http://aka.ms/azstorageclientencryptionblog">Azure Storage Client Encryption Blog.</a>
23+
</li>
24+
<li>
25+
<a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-30187">CVE-2022-30187</a>
26+
</li>
27+
28+
</references>
29+
</qhelp>
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* @name Unsafe usage of v1 version of Azure Storage client-side encryption (CVE-2022-30187).
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 constructor
18+
*/
19+
predicate isCreatingAzureClientSideEncryptionObject(ObjectCreation oc, Class c, Expr e) {
20+
exists(Parameter p | p.hasName("version") |
21+
c.hasQualifiedName("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.hasQualifiedName("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 known to support
37+
* version 2+ for client-side encryption
38+
*/
39+
predicate doesAzureStorageAssemblySupportSafeClientSideEncryption(Assembly asm) {
40+
exists(int versionCompare |
41+
versionCompare = asm.getVersion().compareTo("12.12.0.0") and
42+
versionCompare >= 0
43+
) and
44+
asm.getName() = "Azure.Storage.Common"
45+
}
46+
47+
/**
48+
* Holds if the Azure.Storage assembly for `c` is a version known to support
49+
* version 2+ for client-side encryption and if the argument for the constructor `version`
50+
* is set to a secure value.
51+
*/
52+
predicate isObjectCreationArgumentSafeAndUsingSafeVersionOfAssembly(Expr versionExpr, Assembly asm) {
53+
// Check if the Azure.Storage assembly version has the fix
54+
doesAzureStorageAssemblySupportSafeClientSideEncryption(asm) and
55+
// and that the version argument for the constructor is guaranteed to be Version2
56+
isExprAnAccessToSafeClientSideEncryptionVersionValue(versionExpr)
57+
}
58+
59+
/**
60+
* Holds if the expression `e` is an access to a safe version of the enum `ClientSideEncryptionVersion`
61+
* or an equivalent numeric value
62+
*/
63+
predicate isExprAnAccessToSafeClientSideEncryptionVersionValue(Expr e) {
64+
exists(EnumConstant ec |
65+
ec.hasQualifiedName("Azure.Storage.ClientSideEncryptionVersion.V2_0") and
66+
ec.getAnAccess() = e
67+
)
68+
}
69+
70+
from Expr e, Class c, Assembly asm
71+
where
72+
asm = c.getLocation() and
73+
(
74+
exists(Expr e2 |
75+
isCreatingAzureClientSideEncryptionObject(e, c, e2) and
76+
not isObjectCreationArgumentSafeAndUsingSafeVersionOfAssembly(e2, asm)
77+
)
78+
or
79+
isCreatingOutdatedAzureClientSideEncryptionObject(e, c)
80+
)
81+
select e, "Unsafe usage of v1 version of Azure Storage client-side encryption."
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: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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>The Azure Storage SDK version 12.18.0 or later supports version <code>V2</code> for client-side encryption. All previous versions of Azure Storage SDK only support client-side encryption <code>V1</code> which is unsafe.</p>
8+
9+
</overview>
10+
<recommendation>
11+
12+
<p>Consider switching to <code>V2</code> client-side encryption.</p>
13+
14+
</recommendation>
15+
<example>
16+
17+
<sample src="UnsafeUsageOfClientSideEncryptionVersion.java" />
18+
19+
</example>
20+
<references>
21+
<li>
22+
<a href="http://aka.ms/azstorageclientencryptionblog">Azure Storage Client Encryption Blog.</a>
23+
</li>
24+
<li>
25+
<a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-30187">CVE-2022-30187</a>
26+
</li>
27+
28+
</references>
29+
</qhelp>
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/**
2+
* @name Unsafe usage of v1 version of Azure Storage client-side encryption (CVE-2022-30187).
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+
import semmle.code.java.dataflow.DataFlow
15+
16+
/**
17+
* Holds if `call` is an object creation for a class `EncryptedBlobClientBuilder`
18+
* that takes no arguments, which means that it is using V1 encryption.
19+
*/
20+
predicate isCreatingOutdatedAzureClientSideEncryptionObject(Call call, Class c) {
21+
exists(string package, string type, Constructor constructor |
22+
c.hasQualifiedName(package, type) and
23+
c.getAConstructor() = constructor and
24+
call.getCallee() = constructor and
25+
(
26+
type = "EncryptedBlobClientBuilder" and
27+
package = "com.azure.storage.blob.specialized.cryptography" and
28+
constructor.hasNoParameters()
29+
or
30+
type = "BlobEncryptionPolicy" and package = "com.microsoft.azure.storage.blob"
31+
)
32+
)
33+
}
34+
35+
/**
36+
* Holds if `call` is an object creation for a class `EncryptedBlobClientBuilder`
37+
* that takes `versionArg` as the argument specifying the encryption version.
38+
*/
39+
predicate isCreatingAzureClientSideEncryptionObjectNewVersion(Call call, Class c, Expr versionArg) {
40+
exists(string package, string type, Constructor constructor |
41+
c.hasQualifiedName(package, type) and
42+
c.getAConstructor() = constructor and
43+
call.getCallee() = constructor and
44+
type = "EncryptedBlobClientBuilder" and
45+
package = "com.azure.storage.blob.specialized.cryptography" and
46+
versionArg = call.getArgument(0)
47+
)
48+
}
49+
50+
/**
51+
* A dataflow config that tracks `EncryptedBlobClientBuilder.version` argument initialization.
52+
*/
53+
private class EncryptedBlobClientBuilderSafeEncryptionVersionConfig extends DataFlow::Configuration {
54+
EncryptedBlobClientBuilderSafeEncryptionVersionConfig() {
55+
this = "EncryptedBlobClientBuilderSafeEncryptionVersionConfig"
56+
}
57+
58+
override predicate isSource(DataFlow::Node source) {
59+
exists(FieldRead fr, Field f | fr = source.asExpr() |
60+
f.getAnAccess() = fr and
61+
f.hasQualifiedName("com.azure.storage.blob.specialized.cryptography", "EncryptionVersion",
62+
"V2")
63+
)
64+
}
65+
66+
override predicate isSink(DataFlow::Node sink) {
67+
isCreatingAzureClientSideEncryptionObjectNewVersion(_, _, sink.asExpr())
68+
}
69+
}
70+
71+
/**
72+
* Holds if `call` is an object creation for a class `EncryptedBlobClientBuilder`
73+
* that takes `versionArg` as the argument specifying the encryption version, and that version is safe.
74+
*/
75+
predicate isCreatingSafeAzureClientSideEncryptionObject(Call call, Class c, Expr versionArg) {
76+
isCreatingAzureClientSideEncryptionObjectNewVersion(call, c, versionArg) and
77+
exists(EncryptedBlobClientBuilderSafeEncryptionVersionConfig config, DataFlow::Node sink |
78+
sink.asExpr() = versionArg
79+
|
80+
config.hasFlow(_, sink)
81+
)
82+
}
83+
84+
from Expr e, Class c
85+
where
86+
exists(Expr argVersion |
87+
isCreatingAzureClientSideEncryptionObjectNewVersion(e, c, argVersion) and
88+
not isCreatingSafeAzureClientSideEncryptionObject(e, c, argVersion)
89+
)
90+
or
91+
isCreatingOutdatedAzureClientSideEncryptionObject(e, c)
92+
select e, "Unsafe usage of v1 version of Azure Storage client-side encryption."
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: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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>v2</code> client-side encryption.</p>
13+
14+
</recommendation>
15+
<example>
16+
17+
<sample src="UnsafeUsageOfClientSideEncryptionVersion.py" />
18+
19+
</example>
20+
<references>
21+
<li>
22+
<a href="http://aka.ms/azstorageclientencryptionblog">Azure Storage Client Encryption Blog.</a>
23+
</li>
24+
<li>
25+
<a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-30187">CVE-2022-30187</a>
26+
</li>
27+
28+
</references>
29+
</qhelp>

0 commit comments

Comments
 (0)