Merge pull request #9776 from raulgarciamsft/azure-sdk-client-encryption-version

New queries to detect unsafe client side encryption in Azure Storage
This commit is contained in:
yo-h
2022-07-16 14:59:51 -04:00
committed by GitHub
9 changed files with 447 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
// BAD: Using an outdated SDK that does not support client side encryption version V2_0
new EncryptedBlobClientBuilder()
.blobClient(blobClient)
.key(resolver.buildAsyncKeyEncryptionKey(keyid).block(), keyWrapAlgorithm)
.buildEncryptedBlobClient()
.uploadWithResponse(new BlobParallelUploadOptions(data)
.setMetadata(metadata)
.setHeaders(headers)
.setTags(tags)
.setTier(tier)
.setRequestConditions(requestConditions)
.setComputeMd5(computeMd5)
.setParallelTransferOptions(parallelTransferOptions),
timeout, context);
// BAD: Using the deprecatedd client side encryption version V1_0
new EncryptedBlobClientBuilder(EncryptionVersion.V1)
.blobClient(blobClient)
.key(resolver.buildAsyncKeyEncryptionKey(keyid).block(), keyWrapAlgorithm)
.buildEncryptedBlobClient()
.uploadWithResponse(new BlobParallelUploadOptions(data)
.setMetadata(metadata)
.setHeaders(headers)
.setTags(tags)
.setTier(tier)
.setRequestConditions(requestConditions)
.setComputeMd5(computeMd5)
.setParallelTransferOptions(parallelTransferOptions),
timeout, context);
// GOOD: Using client side encryption version V2_0
new EncryptedBlobClientBuilder(EncryptionVersion.V2)
.blobClient(blobClient)
.key(resolver.buildAsyncKeyEncryptionKey(keyid).block(), keyWrapAlgorithm)
.buildEncryptedBlobClient()
.uploadWithResponse(new BlobParallelUploadOptions(data)
.setMetadata(metadata)
.setHeaders(headers)
.setTags(tags)
.setTier(tier)
.setRequestConditions(requestConditions)
.setComputeMd5(computeMd5)
.setParallelTransferOptions(parallelTransferOptions),
timeout, context);

View File

@@ -0,0 +1,29 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<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>
<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>
</overview>
<recommendation>
<p>Consider switching to <code>V2</code> client-side encryption.</p>
</recommendation>
<example>
<sample src="UnsafeUsageOfClientSideEncryptionVersion.java" />
</example>
<references>
<li>
<a href="http://aka.ms/azstorageclientencryptionblog">Azure Storage Client Encryption Blog.</a>
</li>
<li>
<a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-30187">CVE-2022-30187</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,92 @@
/**
* @name Unsafe usage of v1 version of Azure Storage client-side encryption (CVE-2022-30187).
* @description Unsafe usage of v1 version of Azure Storage client-side encryption, please refer to http://aka.ms/azstorageclientencryptionblog
* @kind problem
* @tags security
* cryptography
* external/cwe/cwe-327
* @id java/azure-storage/unsafe-client-side-encryption-in-use
* @problem.severity error
* @precision high
*/
import java
import semmle.code.java.dataflow.DataFlow
/**
* Holds if `call` is an object creation for a class `EncryptedBlobClientBuilder`
* that takes no arguments, which means that it is using V1 encryption.
*/
predicate isCreatingOutdatedAzureClientSideEncryptionObject(Call call, Class c) {
exists(string package, string type, Constructor constructor |
c.hasQualifiedName(package, type) and
c.getAConstructor() = constructor and
call.getCallee() = constructor and
(
type = "EncryptedBlobClientBuilder" and
package = "com.azure.storage.blob.specialized.cryptography" and
constructor.hasNoParameters()
or
type = "BlobEncryptionPolicy" and package = "com.microsoft.azure.storage.blob"
)
)
}
/**
* Holds if `call` is an object creation for a class `EncryptedBlobClientBuilder`
* that takes `versionArg` as the argument specifying the encryption version.
*/
predicate isCreatingAzureClientSideEncryptionObjectNewVersion(Call call, Class c, Expr versionArg) {
exists(string package, string type, Constructor constructor |
c.hasQualifiedName(package, type) and
c.getAConstructor() = constructor and
call.getCallee() = constructor and
type = "EncryptedBlobClientBuilder" and
package = "com.azure.storage.blob.specialized.cryptography" and
versionArg = call.getArgument(0)
)
}
/**
* A dataflow config that tracks `EncryptedBlobClientBuilder.version` argument initialization.
*/
private class EncryptedBlobClientBuilderSafeEncryptionVersionConfig extends DataFlow::Configuration {
EncryptedBlobClientBuilderSafeEncryptionVersionConfig() {
this = "EncryptedBlobClientBuilderSafeEncryptionVersionConfig"
}
override predicate isSource(DataFlow::Node source) {
exists(FieldRead fr, Field f | fr = source.asExpr() |
f.getAnAccess() = fr and
f.hasQualifiedName("com.azure.storage.blob.specialized.cryptography", "EncryptionVersion",
"V2")
)
}
override predicate isSink(DataFlow::Node sink) {
isCreatingAzureClientSideEncryptionObjectNewVersion(_, _, sink.asExpr())
}
}
/**
* Holds if `call` is an object creation for a class `EncryptedBlobClientBuilder`
* that takes `versionArg` as the argument specifying the encryption version, and that version is safe.
*/
predicate isCreatingSafeAzureClientSideEncryptionObject(Call call, Class c, Expr versionArg) {
isCreatingAzureClientSideEncryptionObjectNewVersion(call, c, versionArg) and
exists(EncryptedBlobClientBuilderSafeEncryptionVersionConfig config, DataFlow::Node sink |
sink.asExpr() = versionArg
|
config.hasFlow(_, sink)
)
}
from Expr e, Class c
where
exists(Expr argVersion |
isCreatingAzureClientSideEncryptionObjectNewVersion(e, c, argVersion) and
not isCreatingSafeAzureClientSideEncryptionObject(e, c, argVersion)
)
or
isCreatingOutdatedAzureClientSideEncryptionObject(e, c)
select e, "Unsafe usage of v1 version of Azure Storage client-side encryption."