Modify S6437: Change text to LaYC format (APPSEC-1111) (#3165)

This commit is contained in:
gaetan-ferry-sonarsource 2023-09-29 14:44:00 +02:00 committed by GitHub
parent 86607c7d86
commit 2b814963d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 190 additions and 219 deletions

View File

@ -0,0 +1,2 @@
The following code example is noncompliant because it uses a hardcoded secret
value.

View File

@ -0,0 +1,9 @@
=== How does this work?
While the noncompliant code example contains a hard-coded password, the
compliant solution retrieves the secret's value from its environment. This
allows to have an environment-dependent secret value and avoids storing the
password in the source code itself.
Depending on the application and its underlying infrastructure, how the secret
gets added to the environment might change.

View File

@ -0,0 +1,2 @@
The consequences vary greatly depending on the situation and the secret-exposed
audience. Still, two main scenarios should be considered.

View File

@ -0,0 +1,6 @@
=== Documentation
* AWS Documentation - https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html[What is AWS Secrets Manager]
* Azure Documentation - https://learn.microsoft.com/en-us/azure/key-vault/[Azure Key Vault]
* Google Cloud - https://cloud.google.com/secret-manager/docs[Secret Manager documentation]
* HashiCorp Developer - https://developer.hashicorp.com/vault/docs[Vault Documentation]

View File

@ -0,0 +1,6 @@
=== Standards
* OWASP - https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures/[Top 10 2021 - Category A7 - Identification and Authentication Failures]
* OWASP - https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication[Top 10 2017 - Category A2 - Broken Authentication]
* CWE - https://cwe.mitre.org/data/definitions/798.html[CWE-798 - Use of Hard-coded Credentials]
* CWE - https://cwe.mitre.org/data/definitions/259.html[CWE-259 - Use of Hard-coded Password]

View File

@ -1,32 +0,0 @@
A hard-coded secret has been found in your code. You should quickly list where
this secret is used, revoke it, and then change it in every system that uses
it.
Passwords, secrets, and any type of credentials should only be used to
authenticate a single entity (a person or a system).
If you allow third parties to authenticate as another system or person, they
can impersonate legitimate identities and undermine trust within the
organization. +
It does not matter if the impersonation is malicious: In either case, it is a
clear breach of trust in the system, as the systems involved falsely assume
that the authenticated entity is who it claims to be. +
The consequences can be catastrophic.
Keeping credentials in plain text in a code base is tantamount to sharing that
password with anyone who has access to the source code and runtime servers. +
Thus, it is a breach of trust, as these individuals have the ability to
impersonate others.
Secret management services are the most efficient tools to store credentials
and protect the identities associated with them. +
Cloud providers and on-premise services can be used for this purpose.
If storing credentials in a secret data management service is not possible,
follow these guidelines:
* Do not store credentials in a file that an excessive number of people can access.
** For example, not in code, not in a spreadsheet, not on a sticky note, and not on a shared drive.
* Use the production operating system to protect password access control.
** For example, in a file whose permissions are restricted and protected with chmod and chown.

View File

@ -1,36 +1,47 @@
include::../../../shared_content/secrets/description.adoc[]
== Why is this an issue?
Sensitive data has been found in the Dockerfile or Docker image. The data
should be considered breached.
include::../../../shared_content/secrets/rationale.adoc[]
If malicious third parties can get a hold of such information, they could
impersonate legitimate identities within the organization. +
It is a clear breach of trust in the system, as the systems involved falsely
assume that the authenticated entity is who it claims to be. +
The consequences can be catastrophic.
In Dockerfiles, secrets hard-coded, secrets passed through as variables or
In Dockerfiles, hard-coded secrets and secrets passed through as variables or
created at build-time will cause security risks. The secret information can be
exposed either via the container environment itself, the image metadata or the
build environment logs.
exposed either via the container environment, the image metadata, or the build
environment logs.
Docker Buildkit's secret mount options should be used when secrets have to be
accessed at build time. For run-time secrets, best practices would recommend
only setting them at runtime, for example with the `--env` option of the docker
run command.
=== What is the potential impact?
Note that files exposing the secrets should be securely stored and not exposed
to a large sphere. If possible, use a secret vault or another similar
component. For example, *Docker Swarm* provides a *secrets* service that can be
used to handle most confidential data.
include::../common/impact/rationale.adoc[]
include::../../../shared_content/secrets/impact/financial_loss.adoc[]
=== Noncompliant code example
include::../../../shared_content/secrets/impact/security_downgrade.adoc[]
The following code snippet demonstrates the creation of a file with a private
key and a public key, which are then stored in the metadata of the container. +
This is non-compliant, as the private key should not be exposed anywhere.
== How to fix it
Best practices recommend using a secret vault for all secrets that must be
accessed at container runtime. This will ensure the secret's security and
prevent any further unexpected disclosure. Depending on the development platform
and the leaked secret type, multiple solutions are currently available.
For all secrets that must be accessed at image build time, it is recommended to
rely on Docker Buildkit's secret mount options. This will prevent secrets from
being disclosed in image's metadata and build logs.
Additionally, investigations and remediation actions should be conducted to
ensure the current and future security of the infrastructure.
include::../../../shared_content/secrets/fix/revoke.adoc[]
include::../../../shared_content/secrets/fix/recent_use.adoc[]
=== Code examples
==== Noncompliant code example
The following code sample generates a new SSH private key that will be stored in
the generated image. This key should be considered as compromised. Moreover, the
SSH key encryption passphrase is also hardcoded.
[source,docker, diff-id=1, diff-type=noncompliant]
----
@ -42,8 +53,8 @@ RUN ssh-keygen -N "passphrase" -t rsa -b 2048 -f /etc/ssh/rsa_key
RUN /example.sh --ssh /etc/ssh/rsa_key
----
In the following sample, the code uses a seemingly-hidden password which is
actually leaked after the container is built.
The following code sample uses a seemingly hidden password which is actually
leaked in the image metadata after the build.
[source,docker, diff-id=2, diff-type=noncompliant]
----
@ -54,12 +65,9 @@ ARG PASSWORD
RUN wget --user=guest --password="$PASSWORD" https://example.com
----
=== Compliant solution
==== Compliant solution
For build-time secrets, use
https://docs.docker.com/engine/reference/builder/#run---mounttypesecret[Buildkit's secret mount type] instead:
[source,docker, diff-id=1, diff-type=compliant]
[source,docker,diff-id=1,diff-type=compliant]
----
FROM example
@ -67,16 +75,19 @@ RUN --mount=type=secret,id=ssh,target=/etc/ssh/rsa_key \
/example.sh --ssh /etc/ssh/rsa_key
----
[source,docker, diff-id=2, diff-type=compliant]
[source,docker,diff-id=2,diff-type=compliant]
----
FROM example
RUN --mount=type=secret,id=wget_passwd \
wget --user=guest --password="$(cat /run/secrets/wget_passwd)" https://example.com
RUN --mount=type=secret,id=wget,target=/home/user/.wgetrc \
wget --user=guest https://example.com
----
For runtime secrets, leave the environment variables empty in the Dockerfile.
Then store the runtime secrets in an
For runtime secrets, best practices recommend relying on a vault service to
pass secret information to the containers. Docker environment provides Swarm
services that implement such a feature.
If such an option can not be considered, store the runtime secrets in an
https://docs.docker.com/compose/env-file/[environment file] such as `.env` and
then start the container with the
https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file[`--env-file`] argument:
@ -86,13 +97,20 @@ https://docs.docker.com/engine/reference/commandline/run/#set-environment-variab
docker run --env-file .env myImage
----
It is then important to ensure that the environment files are securely stored
and generated.
== Resources
* https://docs.docker.com/engine/reference/builder/#run---mounttypesecret[Dockerfile reference] - RUN command secrets mount points
* https://docs.docker.com/engine/swarm/secrets/[Docker documentation] - Manage sensitive data with Docker secrets
* https://cwe.mitre.org/data/definitions/522.html[MITRE, CWE-522] - Insufficiently Protected Credentials
* https://cwe.mitre.org/data/definitions/798.html[MITRE, CWE-798] - Use of Hard-coded Credentials
include::../common/resources/documentation.adoc[]
* Docker Documentation - https://docs.docker.com/engine/swarm/secrets/[Manage sensitive data with Docker secrets]
* Docker Documentation - https://docs.docker.com/engine/reference/builder/#run---mounttypesecret[RUN command secrets mount points]
=== Standards
* CWE - https://cwe.mitre.org/data/definitions/522.html[CWE-522 - Insufficiently Protected Credentials]
* CWE - https://cwe.mitre.org/data/definitions/798.html[CWE-798 - Use of Hard-coded Credentials]
ifdef::env-github,rspecator-view[]
'''
@ -115,5 +133,3 @@ For secret generation:
'''
endif::env-github,rspecator-view[]

View File

@ -1,10 +1,32 @@
include::../../../shared_content/secrets/description.adoc[]
== Why is this an issue?
include::../description.adoc[]
include::../../../shared_content/secrets/rationale.adoc[]
=== Noncompliant code example
=== What is the potential impact?
[source,java]
include::../common/impact/rationale.adoc[]
include::../../../shared_content/secrets/impact/financial_loss.adoc[]
include::../../../shared_content/secrets/impact/security_downgrade.adoc[]
== How to fix it
include::../../../shared_content/secrets/fix/revoke.adoc[]
include::../../../shared_content/secrets/fix/recent_use.adoc[]
include::../../../shared_content/secrets/fix/vault.adoc[]
=== Code examples
include::../common/fix/code-rationale.adoc[]
==== Noncompliant code example
[source,java,diff-id=1,diff-type=noncompliant]
----
import org.h2.security.SHA256;
@ -14,62 +36,25 @@ byte[] key = inputString.getBytes();
SHA256.getHMAC(key, message); // Noncompliant
----
=== Compliant solution
==== Compliant solution
Using https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/secretsmanager[AWS Secrets Manager]:
[source,java]
[source,java,diff-id=1,diff-type=compliant]
----
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest;
import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse;
import org.h2.security.SHA256;
public static void doSomething(SecretsManagerClient secretsClient, String secretName) {
GetSecretValueRequest valueRequest = GetSecretValueRequest.builder()
.secretId(secretName)
.build();
String inputString = System.getenv("SECRET");
byte[] key = inputString.getBytes();
GetSecretValueResponse valueResponse = secretsClient.getSecretValue(valueRequest);
String secret = valueResponse.secretString();
byte[] key = secret.getBytes();
SHA256.getHMAC(key, message);
}
----
Using https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-java?tabs=azure-cli[Azure Key Vault Secret]:
[source,java]
----
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.SecretClientBuilder;
import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
import org.h2.security.SHA256;
public static void doSomething(SecretClient secretClient, String secretName) {
KeyVaultSecret retrievedSecret = secretClient.getSecret(secretName);
String secret = retrievedSecret.getValue();
byte[] key = secret.getBytes();
SHA256.getHMAC(key, message);
}
SHA256.getHMAC(key, message); // Noncompliant
----
include::../common/fix/how-it-works.adoc[]
== Resources
* https://aws.amazon.com/fr/secrets-manager/[AWS] - Secret Manager
* https://azure.microsoft.com/fr-fr/services/key-vault/[Azure] - Key Vault
* https://cloud.google.com/secret-manager[GCP] - Secret Manager
* https://www.vaultproject.io/[Hashicorp Vault] - Secret Management
* https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures/[OWASP Top 10 2021 Category A7] - Identification and Authentication Failures
* https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication[OWASP Top 10 2017 Category A2] - Broken Authentication
* https://cwe.mitre.org/data/definitions/798.html[MITRE, CWE-798] - Use of Hard-coded Credentials
* https://cwe.mitre.org/data/definitions/259.html[MITRE, CWE-259] - Use of Hard-coded Password
* https://wiki.sei.cmu.edu/confluence/x/OjdGBQ[CERT, MSC03-J.] - Never hard code sensitive information
include::../common/resources/documentation.adoc[]
include::../common/resources/standards.adoc[]
ifdef::env-github,rspecator-view[]
'''
@ -86,5 +71,3 @@ Highlight the credential use and its initialization.
'''
endif::env-github,rspecator-view[]

View File

@ -1,56 +1,63 @@
include::../../../shared_content/secrets/description.adoc[]
== Why is this an issue?
include::../description.adoc[]
include::../../../shared_content/secrets/rationale.adoc[]
=== Noncompliant code example
=== What is the potential impact?
[source,php]
include::../common/impact/rationale.adoc[]
include::../../../shared_content/secrets/impact/financial_loss.adoc[]
include::../../../shared_content/secrets/impact/security_downgrade.adoc[]
== How to fix it
include::../../../shared_content/secrets/fix/revoke.adoc[]
include::../../../shared_content/secrets/fix/recent_use.adoc[]
include::../../../shared_content/secrets/fix/vault.adoc[]
=== Code examples
include::../common/fix/code-rationale.adoc[]
==== Noncompliant code example
[source,php,diff-id=1,diff-type=noncompliant]
----
use Defuse\Crypto\KeyOrPassword;
function createKey() {
$password = "example";
return KeyOrPassword::createFromPassword($password); // Noncompliant
$password = "3xAmpl3"; // Noncompliant
return KeyOrPassword::createFromPassword($password);
}
----
=== Compliant solution
==== Compliant solution
Modern web frameworks tend to provide a secure way to pass passwords and secrets
to the code. For example, in Symfony you can use https://symfony.com/doc/current/configuration/secrets.html[vaults]
to store your secrets. The secret values are referenced in the same way as
environment variables, so you can easily access them through https://symfony.com/doc/current/configuration.html#configuration-parameters[configuration parameters].
[source,php]
[source,php,diff-id=1,diff-type=compliant]
----
use Defuse\Crypto\KeyOrPassword;
class PasswordService
{
private string $password;
public function setPassword(string $password): void
{
$this->password = $password;
}
public function createKey(): KeyOrPassword
{
return KeyOrPassword::createFromPassword($this->password);
}
function createKey() {
$password = $_ENV["SECRET"]
return KeyOrPassword::createFromPassword($password);
}
----
include::../common/fix/how-it-works.adoc[]
== Resources
* https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures/[OWASP Top 10 2021 Category A7] - Identification and Authentication Failures
* https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication[OWASP Top 10 2017 Category A2] - Broken Authentication
* https://cwe.mitre.org/data/definitions/798.html[MITRE, CWE-798] - Use of Hard-coded Credentials
* https://cwe.mitre.org/data/definitions/259.html[MITRE, CWE-259] - Use of Hard-coded Password
* https://wiki.sei.cmu.edu/confluence/x/OjdGBQ[CERT, MSC03-J.] - Never hard code sensitive information
* https://symfony.com/doc/current/configuration/env_var_processors.html[Symfony] - Environment Variable Processors
* https://symfony.com/doc/current/configuration.html#configuration-parameters[Symfony] - Configuring Symfony
* https://symfony.com/doc/current/configuration/secrets.html[Symfony] - How to Keep Sensitive Information Secret
include::../common/resources/documentation.adoc[]
* Symfony - https://symfony.com/doc/current/configuration/secrets.html[How to
Keep Sensitive Information Secret]
include::../common/resources/standards.adoc[]
ifdef::env-github,rspecator-view[]
'''
@ -67,5 +74,3 @@ Highlight the credential use and its initialization.
'''
endif::env-github,rspecator-view[]

View File

@ -1,10 +1,32 @@
include::../../../shared_content/secrets/description.adoc[]
== Why is this an issue?
include::../description.adoc[]
include::../../../shared_content/secrets/rationale.adoc[]
=== Noncompliant code example
=== What is the potential impact?
[source,python]
include::../common/impact/rationale.adoc[]
include::../../../shared_content/secrets/impact/financial_loss.adoc[]
include::../../../shared_content/secrets/impact/security_downgrade.adoc[]
== How to fix it
include::../../../shared_content/secrets/fix/revoke.adoc[]
include::../../../shared_content/secrets/fix/recent_use.adoc[]
include::../../../shared_content/secrets/fix/vault.adoc[]
=== Code examples
include::../common/fix/code-rationale.adoc[]
==== Noncompliant code example
[source,python,diff-id=1,diff-type=noncompliant]
----
from requests_oauthlib.oauth2_session import OAuth2Session
@ -18,27 +40,15 @@ oauth = OAuth2Session(
token = oauth.fetch_token(
'https://api.example.com/o/oauth2/token',
client_secret='example_Password') # Noncompliant
data = oauth.get('https://www.api.example.com/oauth2/v1/exampledata')
----
=== Compliant solution
==== Compliant solution
Using https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/secretsmanager[AWS Secrets Manager]:
[source,python]
[source,python,diff-id=1,diff-type=compliant]
----
import boto3
from os import environ
from requests_oauthlib.oauth2_session import OAuth2Session
def get_client_secret():
session = boto3.session.Session()
client = session.client(service_name='secretsmanager', region_name='eu-west-1')
return client.get_secret_value(SecretId='example_oauth_secret_id')
client_secret = get_client_secret()
scope = ['https://www.api.example.com/auth/example.data']
oauth = OAuth2Session(
@ -46,54 +56,20 @@ oauth = OAuth2Session(
redirect_uri='https://callback.example.com/uri',
scope=scope)
token = oauth.fetch_token(
'https://api.example.com/o/oauth2/token',
client_secret=client_secret)
data = oauth.get('https://www.api.example.com/oauth2/v1/exampledata')
----
Using https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-java?tabs=azure-cli[Azure Key Vault Secret]:
[source,python]
----
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential
def get_client_secret():
vault_uri = "https://example.vault.azure.net"
credential = DefaultAzureCredential()
client = SecretClient(vault_url=vault_uri, credential=credential)
return client.get_secret('example_oauth_secret_name')
client_secret = get_client_secret()
scope = ['https://www.api.example.com/auth/example.data']
oauth = OAuth2Session(
'example_client_id',
redirect_uri='https://callback.example.com/uri',
scope=scope)
password = environ.get('OAUTH_SECRET')
token = oauth.fetch_token(
'https://api.example.com/o/oauth2/token',
client_secret=client_secret)
data = oauth.get('https://www.api.example.com/oauth2/v1/exampledata')
client_secret=password)
----
include::../common/fix/how-it-works.adoc[]
== Resources
* https://aws.amazon.com/fr/secrets-manager/[AWS] - Secret Manager
* https://azure.microsoft.com/fr-fr/services/key-vault/[Azure] - Key Vault
* https://cloud.google.com/secret-manager[GCP] - Secret Manager
* https://www.vaultproject.io/[Hashicorp Vault] - Secret Management
* https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures/[OWASP Top 10 2021 Category A7] - Identification and Authentication Failures
* https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication[OWASP Top 10 2017 Category A2] - Broken Authentication
* https://cwe.mitre.org/data/definitions/798.html[MITRE, CWE-798] - Use of Hard-coded Credentials
* https://cwe.mitre.org/data/definitions/259.html[MITRE, CWE-259] - Use of Hard-coded Password
* https://wiki.sei.cmu.edu/confluence/x/OjdGBQ[CERT, MSC03-J.] - Never hard code sensitive information
include::../common/resources/documentation.adoc[]
include::../common/resources/standards.adoc[]
ifdef::env-github,rspecator-view[]
'''
@ -110,5 +86,3 @@ Highlight the credential use and its initialization.
'''
endif::env-github,rspecator-view[]