From 0c49937480b91951a1fb2ab94ac190281db730cd Mon Sep 17 00:00:00 2001 From: Jeremi Do Dinh Date: Mon, 25 Sep 2023 11:03:09 +0200 Subject: [PATCH] Update rule metadata. (#1581) --- .../org/sonar/l10n/py/rules/python/S1763.html | 1 + .../org/sonar/l10n/py/rules/python/S2115.html | 144 +++++-- .../org/sonar/l10n/py/rules/python/S2115.json | 2 +- .../org/sonar/l10n/py/rules/python/S2755.html | 4 +- .../org/sonar/l10n/py/rules/python/S3329.html | 20 +- .../org/sonar/l10n/py/rules/python/S4423.html | 8 +- .../org/sonar/l10n/py/rules/python/S4830.html | 10 +- .../org/sonar/l10n/py/rules/python/S5542.html | 20 +- .../org/sonar/l10n/py/rules/python/S5547.html | 12 +- .../org/sonar/l10n/py/rules/python/S5659.html | 4 +- .../org/sonar/l10n/py/rules/python/S6317.html | 209 +++------- .../org/sonar/l10n/py/rules/python/S6317.json | 2 +- .../org/sonar/l10n/py/rules/python/S6661.json | 2 +- .../org/sonar/l10n/py/rules/python/S6711.html | 385 ++++++++++++++++++ .../org/sonar/l10n/py/rules/python/S6714.html | 2 +- .../org/sonar/l10n/py/rules/python/S6729.html | 2 +- .../org/sonar/l10n/py/rules/python/S6730.json | 5 +- sonarpedia.json | 2 +- 18 files changed, 601 insertions(+), 233 deletions(-) diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S1763.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S1763.html index 899ccf0231..3f9004b810 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S1763.html +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S1763.html @@ -1,3 +1,4 @@ +

Once control flow has been moved out of the current code block, any subsequent statements become effectively unreachable.

Why is this an issue?

Jump statements (return, break, continue, and raise) move control flow out of the current code block. So any statements that come after a jump are dead code.

diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2115.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2115.html index 74bcea9af7..863d86a17b 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2115.html +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2115.html @@ -1,14 +1,102 @@ +

When accessing a database, an empty password should be avoided as it introduces a weakness.

Why is this an issue?

-

When relying on the password authentication mode for the database connection, a secure password should be chosen.

-

This rule raises an issue when an empty password is used.

-

Noncompliant code example

-

Flask-SQLAlchemy

-
+

When a database does not require a password for authentication, it allows anyone to access and manipulate the data stored within it. Exploiting +this vulnerability typically involves identifying the target database and establishing a connection to it without the need for any authentication +credentials.

+

What is the potential impact?

+

Once connected, an attacker can perform various malicious actions, such as viewing, modifying, or deleting sensitive information, potentially +leading to data breaches or unauthorized access to critical systems. It is crucial to address this vulnerability promptly to ensure the security and +integrity of the database and the data it contains.

+

Unauthorized Access to Sensitive Data

+

When a database lacks a password for authentication, it opens the door for unauthorized individuals to gain access to sensitive data. This can +include personally identifiable information (PII), financial records, intellectual property, or any other confidential information stored in the +database. Without proper access controls in place, malicious actors can exploit this vulnerability to retrieve sensitive data, potentially leading to +identity theft, financial loss, or reputational damage.

+

Compromise of System Integrity

+

Without a password requirement, unauthorized individuals can gain unrestricted access to a database, potentially compromising the integrity of the +entire system. Attackers can inject malicious code, alter configurations, or manipulate data within the database, leading to system malfunctions, +unauthorized system access, or even complete system compromise. This can disrupt business operations, cause financial losses, and expose the +organization to further security risks.

+

Unwanted Modifications or Deletions

+

The absence of a password for database access allows anyone to make modifications or deletions to the data stored within it. This poses a +significant risk, as unauthorized changes can lead to data corruption, loss of critical information, or the introduction of malicious content. For +example, an attacker could modify financial records, tamper with customer orders, or delete important files, causing severe disruptions to business +processes and potentially leading to financial and legal consequences.

+

Overall, the lack of a password configured to access a database poses a serious security risk, enabling unauthorized access, data breaches, system +compromise, and unwanted modifications or deletions. It is essential to address this vulnerability promptly to safeguard sensitive data, maintain +system integrity, and protect the organization from potential harm.

+

How to fix it in MySQL Connector/Python

+

Code examples

+

The following code uses an empty password to connect to a MySQL database.

+

The vulnerability can be fixed by using a strong password retrieved from an environment variable DB_PASSWORD. This environment +variable is set during deployment. It should be strong and different for each database.

+

Noncompliant code example

+
+from mysql.connector import connection
+
+connection.MySQLConnection(host='localhost', user='sonarsource', password='')  # Noncompliant
+
+

Compliant solution

+
+from mysql.connector import connection
+import os
+
+db_password = os.getenv('DB_PASSWORD')
+connection.MySQLConnection(host='localhost', user='sonarsource', password=db_password)
+
+

Pitfalls

+

Hard-coded passwords

+

It could be tempting to replace the empty password with a hard-coded one. Hard-coding passwords in the code can pose significant security risks. +Here are a few reasons why it is not recommended:

+
    +
  1. Security Vulnerability: Hard-coded passwords can be easily discovered by anyone who has access to the code, such as other developers or + attackers. This can lead to unauthorized access to the database and potential data breaches.
  2. +
  3. Lack of Flexibility: Hard-coded passwords make it difficult to change the password without modifying the code. If the password needs to be + updated, it would require recompiling and redeploying the code, which can be time-consuming and error-prone.
  4. +
  5. Version Control Issues: Storing passwords in code can lead to version control issues. If the code is shared or stored in a version control + system, the password will be visible to anyone with access to the repository, which is a security risk.
  6. +
+

To mitigate these risks, it is recommended to use secure methods for storing and retrieving passwords, such as using environment variables, +configuration files, or secure key management systems. These methods allow for better security, flexibility, and separation of sensitive information +from the codebase.

+

How to fix it in SQLAlchemy

+

Code examples

+

The following code uses an empty password to connect to a Postgres database.

+

The vulnerability can be fixed by using a strong password retrieved from an environment variable DB_PASSWORD. This environment +variable is set during deployment. It should be strong and different for each database.

+

Noncompliant code example

+
 def configure_app(app):
     app.config['SQLALCHEMY_DATABASE_URI'] = "postgresql://user:@domain.com" # Noncompliant
 
-

Django

-
+

Compliant solution

+
+def configure_app(app):
+    db_password = os.getenv('DB_PASSWORD')
+    app.config['SQLALCHEMY_DATABASE_URI'] = f"postgresql://user:{db_password}@domain.com"
+
+

Pitfalls

+

Hard-coded passwords

+

It could be tempting to replace the empty password with a hard-coded one. Hard-coding passwords in the code can pose significant security risks. +Here are a few reasons why it is not recommended:

+
    +
  1. Security Vulnerability: Hard-coded passwords can be easily discovered by anyone who has access to the code, such as other developers or + attackers. This can lead to unauthorized access to the database and potential data breaches.
  2. +
  3. Lack of Flexibility: Hard-coded passwords make it difficult to change the password without modifying the code. If the password needs to be + updated, it would require recompiling and redeploying the code, which can be time-consuming and error-prone.
  4. +
  5. Version Control Issues: Storing passwords in code can lead to version control issues. If the code is shared or stored in a version control + system, the password will be visible to anyone with access to the repository, which is a security risk.
  6. +
+

To mitigate these risks, it is recommended to use secure methods for storing and retrieving passwords, such as using environment variables, +configuration files, or secure key management systems. These methods allow for better security, flexibility, and separation of sensitive information +from the codebase.

+

How to fix it in Django

+

Code examples

+

The following code uses an empty password to connect to a Postgres database.

+

The vulnerability can be fixed by using a strong password retrieved from an environment variable DB_PASSWORD. This environment +variable is set during deployment. It should be strong and different for each database.

+

Noncompliant code example

+
 # settings.py
 
 DATABASES = {
@@ -22,20 +110,8 @@ 

Noncompliant code example

} }
-

mysql/mysql-connector-python

-
-from mysql.connector import connection
-
-connection.MySQLConnection(host='localhost', user='sonarsource', password='')  # Noncompliant
-
-

Compliant solution

-

Flask-SQLAlchemy

-
-def configure_app(app, pwd):
-    app.config['SQLALCHEMY_DATABASE_URI'] = f"postgresql://user:{pwd}@domain.com" # Compliant
-
-

Django

-
+

Compliant solution

+
 # settings.py
 import os
 
@@ -44,21 +120,29 @@ 

Compliant solution

'ENGINE': 'django.db.backends.postgresql', 'NAME': 'quickdb', 'USER': 'sonarsource', - 'PASSWORD': os.getenv('DB_PASSWORD'), # Compliant + 'PASSWORD': os.getenv('DB_PASSWORD'), 'HOST': 'localhost', 'PORT': '5432' } }
-

mysql/mysql-connector-python

-
-from mysql.connector import connection
-import os
-
-db_password = os.getenv('DB_PASSWORD')
-connection.MySQLConnection(host='localhost', user='sonarsource', password=db_password)  # Compliant
-
+

Pitfalls

+

Hard-coded passwords

+

It could be tempting to replace the empty password with a hard-coded one. Hard-coding passwords in the code can pose significant security risks. +Here are a few reasons why it is not recommended:

+
    +
  1. Security Vulnerability: Hard-coded passwords can be easily discovered by anyone who has access to the code, such as other developers or + attackers. This can lead to unauthorized access to the database and potential data breaches.
  2. +
  3. Lack of Flexibility: Hard-coded passwords make it difficult to change the password without modifying the code. If the password needs to be + updated, it would require recompiling and redeploying the code, which can be time-consuming and error-prone.
  4. +
  5. Version Control Issues: Storing passwords in code can lead to version control issues. If the code is shared or stored in a version control + system, the password will be visible to anyone with access to the repository, which is a security risk.
  6. +
+

To mitigate these risks, it is recommended to use secure methods for storing and retrieving passwords, such as using environment variables, +configuration files, or secure key management systems. These methods allow for better security, flexibility, and separation of sensitive information +from the codebase.

Resources

+

Standards

  • OWASP Top 10 2021 Category A7 - Identification and Authentication Failures
  • diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2115.json b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2115.json index 8c69298510..4eb7f7a00c 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2115.json +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2115.json @@ -5,7 +5,7 @@ "impacts": { "SECURITY": "HIGH" }, - "attribute": "COMPLETE" + "attribute": "TRUSTWORTHY" }, "status": "ready", "remediation": { diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2755.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2755.html index 85179aed4d..d0c2c0d7ca 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2755.html +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2755.html @@ -22,7 +22,7 @@

    Code examples

    The following code contains examples of XML parsers that have external entity processing enabled. As a result, the parsers are vulnerable to XXE attacks if an attacker can control the XML file that is processed.

    Noncompliant code example

    -
    +
     import xml.sax
     
     parser = xml.sax.make_parser()
    @@ -33,7 +33,7 @@ 

    Noncompliant code example

    Compliant solution

    The SAX parser does not process general external entities by default since version 3.7.1.

    -
    +
     import xml.sax
     
     parser = xml.sax.make_parser()
    diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S3329.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S3329.html
    index e4ddc1ed1d..64d2660040 100644
    --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S3329.html
    +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S3329.html
    @@ -67,14 +67,18 @@ 

    Compliant solution

    How does this work?

    Use unique IVs

    -

    To ensure strong security, the initialization vectors for each encryption operation must be unique and random but they do not have to be -secret.

    +

    To ensure high security, initialization vectors must meet two important criteria:

    +
      +
    • IVs must be unique for each encryption operation.
    • +
    • For CBC and CFB modes, a secure FIPS-compliant random number generator should be used to generate unpredictable IVs.
    • +
    +

    The IV does not need be secret, so the IV or information sufficient to determine the IV may be transmitted along with the ciphertext.

    In the previous non-compliant example, the problem is not that the IV is hard-coded.
    It is that the same IV is used for multiple encryption attempts.

    How to fix it in Cryptodome

    Code examples

    Noncompliant code example

    -
    +
     from Crypto.Cipher import AES
     from Crypto.Random import get_random_bytes
     from Crypto.Util.Padding import pad
    @@ -85,7 +89,7 @@ 

    Noncompliant code example

    Compliant solution

    In this example, the code explicitly uses a number generator that is considered strong.

    -
    +
     from Crypto.Cipher import AES
     from Crypto.Random import get_random_bytes
     from Crypto.Util.Padding import pad
    @@ -96,8 +100,12 @@ 

    Compliant solution

    How does this work?

    Use unique IVs

    -

    To ensure strong security, the initialization vectors for each encryption operation must be unique and random but they do not have to be -secret.

    +

    To ensure high security, initialization vectors must meet two important criteria:

    +
      +
    • IVs must be unique for each encryption operation.
    • +
    • For CBC and CFB modes, a secure FIPS-compliant random number generator should be used to generate unpredictable IVs.
    • +
    +

    The IV does not need be secret, so the IV or information sufficient to determine the IV may be transmitted along with the ciphertext.

    In the previous non-compliant example, the problem is not that the IV is hard-coded.
    It is that the same IV is used for multiple encryption attempts.

    Resources

    diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S4423.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S4423.html index 53daea9665..3ccd7bdd22 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S4423.html +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S4423.html @@ -43,13 +43,13 @@

    Legal and compliance issues

    How to fix it in Python Standard Library

    Code examples

    Noncompliant code example

    -
    +
     import ssl
     
     ssl.SSLContext(ssl.PROTOCOL_SSLv3) # Noncompliant
     

    Compliant solution

    -
    +
     import ssl
     
     context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    @@ -70,13 +70,13 @@ 

    Use TLS v1.2 or TLS v1.3

    How to fix it in OpenSSL

    Code examples

    Noncompliant code example

    -
    +
     from OpenSSL import SSL
     
     SSL.Context(SSL.SSLv3_METHOD)  # Noncompliant
     

    Compliant solution

    -
    +
     from OpenSSL import SSL
     
     context = SSL.Context(SSL.TLS_SERVER_METHOD)
    diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S4830.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S4830.html
    index de1a99505a..70d059030f 100644
    --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S4830.html
    +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S4830.html
    @@ -24,7 +24,7 @@ 

    Code examples

    Certificate validation is not enabled by default when _create_unverified_context is used. It is recommended to use _create_default_https_context instead to create a secure context that validates certificates.

    Noncompliant code example

    -
    +
     import ssl
     
     ctx1 = ssl._create_unverified_context() # Noncompliant
    @@ -34,7 +34,7 @@ 

    Noncompliant code example

    ctx3.verify_mode = ssl.CERT_NONE # Noncompliant

    Compliant solution

    -
    +
     import ssl
     
     ctx = ssl.create_default_context()
    @@ -67,7 +67,7 @@ 

    Noncompliant code example

    ctx2.set_verify(SSL.VERIFY_NONE, verify_callback) # Noncompliant

    Compliant solution

    -
    +
     from OpenSSL import SSL
     
     ctx = SSL.Context(SSL.TLSv1_2_METHOD)
    @@ -91,13 +91,13 @@ 

    Code examples

    The certificate validation gets disabled by setting verify to False. To enable validation set the value to True or do not set verify at all to use the secure default value.

    Noncompliant code example

    -
    +
     import requests
     
     requests.request('GET', 'https://example.com', verify=False) # Noncompliant
     

    Compliant solution

    -
    +
     import requests
     
     # By default, certificate validation is enabled
    diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5542.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5542.html
    index dc103083e2..890db491c2 100644
    --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5542.html
    +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5542.html
    @@ -30,13 +30,13 @@ 

    How to fix it in PyCrypto

    Code examples

    Noncompliant code example

    Example with a symmetric cipher, AES:

    -
    +
     from Crypto.Cipher import AES
     
     AES.new(key, AES.MODE_ECB) # Noncompliant
     

    Example with an asymmetric cipher, RSA:

    -
    +
     from Crypto.Cipher import PKCS1_v1_5
     
     PKCS1_v1_5.new(key) # Noncompliant
    @@ -44,13 +44,13 @@ 

    Noncompliant code example

    Compliant solution

    Since PyCrypto is not supported anymore, another library should be used. In the current context, Cryptodome uses a similar API.

    For the AES symmetric cipher, use the GCM mode:

    -
    +
     from Crypto.Cipher import AES
     
     AES.new(key, AES.MODE_GCM)
     

    For the RSA asymmetric cipher, use the Optimal Asymmetric Encryption Padding (OAEP):

    -
    +
     from Crypto.Cipher import PKCS1_OAEP
     
     PKCS1_OAEP.new(key)
    @@ -167,14 +167,14 @@ 

    How to fix it in Cryptodome

    Code examples

    Noncompliant code example

    Example with a symmetric cipher, AES:

    -
    +
     from Crypto.Cipher import AES     # pycryptodome
     from Cryptodome.Cipher import AES # pycryptodomex
     
     AES.new(key, AES.MODE_ECB)  # Noncompliant
     

    Example with an asymmetric cipher, RSA:

    -
    +
     from Crypto.Cipher import PKCS1_V1_5     # pycryptodome
     from Cryptodome.Cipher import PKCS1_V1_5 # pycryptodomex
     
    @@ -182,14 +182,14 @@ 

    Noncompliant code example

    Compliant solution

    For the AES symmetric cipher, use the GCM mode:

    -
    +
     from Crypto.Cipher import AES     # pycryptodome
     from Cryptodome.Cipher import AES # pycryptodomex
     
     AES.new(key, AES.MODE_GCM)
     

    For the RSA asymmetric cipher, use the Optimal Asymmetric Encryption Padding (OAEP):

    -
    +
     from Crypto.Cipher import PKCS1_V1_5     # pycryptodome
     from Cryptodome.Cipher import PKCS1_V1_5 # pycryptodomex
     
    @@ -217,14 +217,14 @@ 

    For RSA: use the OAEP scheme

    How to fix it in pyDes

    Code examples

    Noncompliant code example

    -
    +
     import pyDes
     
     pyDes.des(key) # Noncompliant
     

    Compliant solution

    Since pyDes only provides DES, it is recommended to use another library like pyca.

    -
    +
     from cryptography.hazmat.primitives.ciphers import (
         Cipher,
         algorithms,
    diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5547.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5547.html
    index 0fbb173d62..6324c1eeb5 100644
    --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5547.html
    +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5547.html
    @@ -49,14 +49,14 @@ 

    How to fix it in pyca

    Code examples

    The following code contains examples of algorithms that are not considered highly resistant to cryptanalysis and thus should be avoided.

    Noncompliant code example

    -
    +
     from cryptography.hazmat.primitives.ciphers import Cipher, algorithms
     from cryptography.hazmat.backends import default_backend
     
     cipher = Cipher(algorithms.TripleDES(key), mode=None, backend=default_backend()) # Noncompliant
     

    Compliant solution

    -
    +
     from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
     from cryptography.hazmat.backends import default_backend
     
    @@ -71,14 +71,14 @@ 

    How to fix it in PyCrypto

    Code examples

    The following code contains examples of algorithms that are not considered highly resistant to cryptanalysis and thus should be avoided.

    Noncompliant code example

    -
    +
     from Crypto.Cipher import DES
     
     cipher = DES.new(key) # Noncompliant
     

    Compliant solution

    PyCrypto is deprecated, thus it is recommended to use another library like pyca.

    -
    +
     from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
     from cryptography.hazmat.backends import default_backend
     
    @@ -93,14 +93,14 @@ 

    How to fix it in pyDes

    Code examples

    The following code contains examples of algorithms that are not considered highly resistant to cryptanalysis and thus should be avoided.

    Noncompliant code example

    -
    +
     import pyDes
     
     cipher = pyDes.des(key) # Noncompliant
     

    Compliant solution

    Since pyDes only provides DES, it is recommended to use another library like pyca.

    -
    +
     from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
     from cryptography.hazmat.backends import default_backend
     
    diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5659.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5659.html
    index b6a42101c7..1766690ba2 100644
    --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5659.html
    +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5659.html
    @@ -62,13 +62,13 @@ 

    How to fix it in python-jwt

    Code examples

    The following code contains an example of JWT decoding without verification of the signature.

    Noncompliant code example

    -
    +
     import python_jwt as jwt
     
     jwt.process_jwt(token) # Noncompliant
     

    Compliant solution

    -
    +
     import python_jwt as jwt
     
     jwt.process_jwt(token)
    diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6317.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6317.html
    index 2c8e3e0e30..49a94feb2b 100644
    --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6317.html
    +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6317.html
    @@ -1,161 +1,32 @@
    +

    Within IAM, identity-based policies grant permissions to users, groups, or roles, and enable specific actions to be performed on designated +resources. When an identity policy inadvertently grants more privileges than intended, certain users or roles might be able to perform more actions +than expected. This can lead to potential security risks, as it enables malicious users to escalate their privileges from a lower level to a higher +level of access.

    Why is this an issue?

    AWS Identity and Access Management (IAM) is the service that defines access to AWS resources. One of the core components of IAM is the policy -which, when attached to an identity or a resource, defines its permissions. Policies granting permission to an Identity (a User, a Group or Role) are -called identity-based policies. They add the ability to an identity to perform a predefined set of actions on a list of resources.

    -

    Here is an example of a policy document defining a limited set of permission that grants a user the ability to manage his own access keys.

    -
    -{
    -    "Version": "2012-10-17",
    -    "Statement": [
    -        {
    -            "Action": [
    -                "iam:CreateAccessKey",
    -                "iam:DeleteAccessKey",
    -                "iam:ListAccessKeys",
    -                "iam:UpdateAccessKey"
    -            ],
    -            "Resource": "arn:aws:iam::245500951992:user/${aws:username}",
    -            "Effect": "Allow",
    -            "Sid": "AllowManageOwnAccessKeys"
    -        }
    -    ]
    -}
    -
    -

    Privilege escalation generally happens when an identity policy gives an identity the ability to grant more privileges than the ones it already has. -Here is another example of a policy document that hides a privilege escalation. It allows an identity to generate a new access key for any user from -the account, including users with high privileges.

    -
    -{
    -    "Version": "2012-10-17",
    -    "Statement": [
    -        {
    -            "Action": [
    -                "iam:CreateAccessKey",
    -                "iam:DeleteAccessKey",
    -                "iam:ListAccessKeys",
    -                "iam:UpdateAccessKey"
    -            ],
    -            "Resource": "*",
    -            "Effect": "Allow",
    -            "Sid": "AllowManageOwnAccessKeys"
    -        }
    -    ]
    -}
    -
    -

    Although it looks like it grants a limited set of permissions, this policy would, in practice, give the highest privileges to the identity it’s -attached to.

    -

    Privilege escalation is a serious issue as it allows a malicious user to easily escalate to a high privilege identity from a low privilege identity -it took control of.

    -

    The example above is just one of many permission escalation vectors. Here is the list of vectors that the rule can detect:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Vector nameSummary

    Create Policy Version

    Create a new IAM policy and set it as default

    Set Default Policy Version

    Set a different IAM policy version as default

    Create AccessKey

    Create a new access key for any user

    Create Login Profile

    Create a login profile with a password chosen by the attacker

    Update Login Profile

    Update the existing password with one chosen by the attacker

    Attach User Policy

    Attach a permissive IAM policy like "AdministratorAccess" to a user the attacker controls

    Attach Group Policy

    Attach a permissive IAM policy like "AdministratorAccess" to a group containing a user the attacker controls

    Attach Role Policy

    Attach a permissive IAM policy like "AdministratorAccess" to a role that can be assumed by the user the attacker controls

    Put User Policy

    Alter the existing inline IAM policy from a user the attacker controls

    Put Group Policy

    Alter the existing inline IAM policy from a group containing a user that the attacker controls

    Put Role Policy

    Alter an existing inline IAM role policy. The rule will then be assumed by the user that the attacker controls

    Add User to Group

    Add a user that the attacker controls to a group that has a larger range of permissions

    Update Assume Role Policy

    Update a role’s "AssumeRolePolicyDocument" to allow a user the attacker controls to assume it

    EC2

    Create an EC2 instance that will execute with high privileges

    Lambda Create and Invoke

    Create a Lambda function that will execute with high privileges and invoke it

    Lambda Create and Add Permission

    Create a Lambda function that will execute with high privileges and grant permission to invoke it to a user or a service

    Lambda triggered with an external event

    Create a Lambda function that will execute with high privileges and link it to an external event

    Update Lambda code

    Update the code of a Lambda function executing with high privileges

    CloudFormation

    Create a CloudFormation stack that will execute with high privileges

    Data Pipeline

    Create a Pipeline that will execute with high privileges

    Glue Development Endpoint

    Create a Glue Development Endpoint that will execute with high privileges

    Update Glue Dev Endpoint

    Update the associated SSH key for the Glue endpoint

    -

    The general recommendation to protect against privilege escalation is to restrict the resources to which sensitive permissions are granted. The -first example above is a good demonstration of sensitive permissions being used with a narrow scope of resources and where no privilege escalation is -possible.

    -

    Noncompliant code example

    -

    The following policy allows an attacker to update the code of any Lambda function. An attacker can achieve privilege escalation by altering the -code of a Lambda that executes with high privileges.

    -
    +which, when attached to an identity or a resource, defines its permissions. Policies granting permission to an identity (a user, a group or a role)
    +are called identity-based policies. They add the ability to an identity to perform a predefined set of actions on a list of resources.

    +

    For such policies, it is easy to define very broad permissions (by using wildcard "*" permissions for example.) This is especially +true if it is not yet clear which permissions will be required for a specific workload or use case. However, it is important to limit the amount of +permissions that are granted and the amount of resources to which these permissions are granted. Doing so ensures that there are no users or roles +that have more permissions than they need.

    +

    If this is not done, it can potentially carry security risks in the case that an attacker gets access to one of these identities.

    +

    What is the potential impact?

    +

    AWS IAM policies that contain overly broad permissions can lead to privilege escalation by granting users more access than necessary. They may be +able to perform actions beyond their intended scope.

    +

    Privilege escalation

    +

    When IAM policies are too permissive, they grant users more privileges than necessary, allowing them to perform actions that they should not be +able to. This can be exploited by attackers to gain unauthorized access to sensitive resources and perform malicious activities.

    +

    For example, if an IAM policy grants a user unrestricted access to all S3 buckets in an AWS account, the user can potentially read, write, and +delete any object within those buckets. If an attacker gains access to this user’s credentials, they can exploit this overly permissive policy to +exfiltrate sensitive data, modify or delete critical files, or even launch further attacks within the AWS environment. This can have severe +consequences, such as data breaches, service disruptions, or unauthorized access to other resources within the AWS account.

    +

    How to fix it in AWS CDK

    +

    Code examples

    +

    In this example, the IAM policy allows an attacker to update the code of any Lambda function. An attacker can achieve privilege escalation by +altering the code of a Lambda that executes with high privileges.

    +

    Noncompliant code example

    +
     from aws_cdk.aws_iam import Effect, PolicyDocument, PolicyStatement
     
     PolicyDocument(
    @@ -168,9 +39,9 @@ 

    Noncompliant code example

    ] )
    -

    Compliant solution

    -

    Narrow the policy such that only updates to the code of certain Lambda functions are allowed.

    -
    +

    Compliant solution

    +

    The policy is narrowed such that only updates to the code of certain Lambda functions (without high privileges) are allowed.

    +
     from aws_cdk.aws_iam import Effect, PolicyDocument, PolicyStatement
     
     PolicyDocument(
    @@ -185,11 +56,27 @@ 

    Compliant solution

    ] )
    +

    How does this work?

    +

    Principle of least privilege

    +

    When creating IAM policies, it is important to adhere to the principle of least privilege. This means that any user or role should only be granted +enough permissions to perform the tasks that they are supposed to, and nothing else.

    +

    To successfully implement this, it is easier to start from nothing and gradually build up all the needed permissions. When starting from a policy +with overly broad permissions which is made stricter at a later time, it can be harder to ensure that there are no gaps that might be forgotten about. +In this case, it might be useful to monitor the users or roles to verify which permissions are used.

    Resources

    +

    Documentation

    + +

    Articles & blog posts

    + +

    Standards

    • OWASP Top 10 2021 Category A1 - Broken Access Control
    • -
    • Rhino Security Labs - AWS IAM Privilege Escalation - – Methods and Mitigation
    • OWASP Top 10 2017 Category A5 - Broken Access Control
    • MITRE, CWE-269 - Improper Privilege Management
    • diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6317.json b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6317.json index c833aa00cb..a7aab64097 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6317.json +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6317.json @@ -1,5 +1,5 @@ { - "title": "AWS IAM policies should not allow privilege escalation", + "title": "AWS IAM policies should limit the scope of permissions given", "type": "VULNERABILITY", "code": { "impacts": { diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6661.json b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6661.json index 96b3bf8c7b..ad3a36184f 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6661.json +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6661.json @@ -1,5 +1,5 @@ { - "title": "Assignments of lambdas to variables should be replaced by function definitions.", + "title": "Assignments of lambdas to variables should be replaced by function definitions", "type": "CODE_SMELL", "status": "ready", "remediation": { diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6711.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6711.html index b3214530a8..d37c8ffc23 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6711.html +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6711.html @@ -9,6 +9,391 @@

      Why is this an issue?

      Instead, the preferred best practice to generate reproducible pseudorandom numbers is to instantiate a numpy.random.Generator object with a seed and reuse it in different parts of the code. This avoids the reliance on a global state. Whenever a new seed is needed, a new generator may be created instead of mutating a global state.

      +

      Below is the list of legacy functions and their alternatives:

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Legacy function name

      numpy.random.Generator alternative

      numpy.random.RandomState.seed

      numpy.random.default_rng

      numpy.random.RandomState.rand

      numpy.random.Generator.random

      numpy.random.RandomState.randn

      numpy.random.Generator.standard_normal

      numpy.random.RandomState.randint

      numpy.random.Generator.integers

      numpy.random.RandomState.random_integers

      numpy.random.Generator.integers

      numpy.random.RandomState.random_sample

      numpy.random.Generator.random

      numpy.random.RandomState.choice

      numpy.random.Generator.choice

      numpy.random.RandomState.bytes

      numpy.random.Generator.bytes

      numpy.random.RandomState.shuffle

      numpy.random.Generator.shuffle

      numpy.random.RandomState.permutation

      numpy.random.Generator.permutation

      numpy.random.RandomState.beta

      numpy.random.Generator.beta

      numpy.random.RandomState.binomial

      numpy.random.Generator.binomial

      numpy.random.RandomState.chisquare

      numpy.random.Generator.chisquare

      numpy.random.RandomState.dirichlet

      numpy.random.Generator.dirichlet

      numpy.random.RandomState.exponential

      numpy.random.Generator.exponential

      numpy.random.RandomState.f

      numpy.random.Generator.f

      numpy.random.RandomState.gamma

      numpy.random.Generator.gamma

      numpy.random.RandomState.geometric

      numpy.random.Generator.geometric

      numpy.random.RandomState.gumbel

      numpy.random.Generator.gumbel

      numpy.random.RandomState.hypergeometric

      numpy.random.Generator.hypergeometric

      numpy.random.RandomState.laplace

      numpy.random.Generator.laplace

      numpy.random.RandomState.logistic

      numpy.random.Generator.logistic

      numpy.random.RandomState.lognormal

      numpy.random.Generator.lognormal

      numpy.random.RandomState.logseries

      numpy.random.Generator.logseries

      numpy.random.RandomState.multinomial

      numpy.random.Generator.multinomial

      numpy.random.RandomState.multivariate_normal

      numpy.random.Generator.multivariate_normal

      numpy.random.RandomState.negative_binomial

      numpy.random.Generator.negative_binomial

      numpy.random.RandomState.noncentral_chisquare

      numpy.random.Generator.noncentral_chisquare

      numpy.random.RandomState.noncentral_f

      numpy.random.Generator.noncentral_f

      numpy.random.RandomState.normal

      numpy.random.Generator.normal

      numpy.random.RandomState.pareto

      numpy.random.Generator.pareto

      numpy.random.RandomState.poisson

      numpy.random.Generator.poisson

      numpy.random.RandomState.power

      numpy.random.Generator.power

      numpy.random.RandomState.rayleigh

      numpy.random.Generator.rayleigh

      numpy.random.RandomState.standard_cauchy

      numpy.random.Generator.standard_cauchy

      numpy.random.RandomState.standard_exponential

      numpy.random.Generator.standard_exponential

      numpy.random.RandomState.standard_gamma

      numpy.random.Generator.standard_gamma

      numpy.random.RandomState.standard_normal

      numpy.random.Generator.standard_normal

      numpy.random.RandomState.standard_t

      numpy.random.Generator.standard_t

      numpy.random.RandomState.triangular

      numpy.random.Generator.triangular

      numpy.random.RandomState.uniform

      numpy.random.Generator.uniform

      numpy.random.RandomState.vonmises

      numpy.random.Generator.vonmises

      numpy.random.RandomState.wald

      numpy.random.Generator.wald

      numpy.random.RandomState.weibull

      numpy.random.Generator.weibull

      numpy.random.RandomState.zipf

      numpy.random.Generator.zipf

      numpy.random.beta

      numpy.random.Generator.beta

      numpy.random.binomial

      numpy.random.Generator.binomial

      numpy.random.bytes

      numpy.random.Generator.bytes

      numpy.random.chisquare

      numpy.random.Generator.chisquare

      numpy.random.choice

      numpy.random.Generator.choice

      numpy.random.dirichlet

      numpy.random.Generator.dirichlet

      numpy.random.exponential

      numpy.random.Generator.exponential

      numpy.random.f

      numpy.random.Generator.f

      numpy.random.gamma

      numpy.random.Generator.gamma

      numpy.random.geometric

      numpy.random.Generator.geometric

      numpy.random.gumbel

      numpy.random.Generator.gumbel

      numpy.random.hypergeometric

      numpy.random.Generator.hypergeometric

      numpy.random.laplace

      numpy.random.Generator.laplace

      numpy.random.logistic

      numpy.random.Generator.logistic

      numpy.random.lognormal

      numpy.random.Generator.lognormal

      numpy.random.logseries

      numpy.random.Generator.logseries

      numpy.random.multinomial

      numpy.random.Generator.multinomial

      numpy.random.multivariate_normal

      numpy.random.Generator.multivariate_normal

      numpy.random.negative_binomial

      numpy.random.Generator.negative_binomial

      numpy.random.noncentral_chisquare

      numpy.random.Generator.noncentral_chisquare

      numpy.random.noncentral_f

      numpy.random.Generator.noncentral_f

      numpy.random.normal

      numpy.random.Generator.normal

      numpy.random.pareto

      numpy.random.Generator.pareto

      numpy.random.permutation

      numpy.random.Generator.permutation

      numpy.random.poisson

      numpy.random.Generator.poisson

      numpy.random.power

      numpy.random.Generator.power

      numpy.random.rand

      numpy.random.Generator.random

      numpy.random.randint

      numpy.random.Generator.integers

      numpy.random.randn

      numpy.random.Generator.standard_normal

      numpy.random.random

      numpy.random.Generator.random

      numpy.random.random_integers

      numpy.random.Generator.integers

      numpy.random.random_sample

      numpy.random.Generator.random

      numpy.random.ranf

      numpy.random.Generator.random

      numpy.random.rayleigh

      numpy.random.Generator.rayleigh

      numpy.random.sample

      numpy.random.Generator.random

      numpy.random.seed

      numpy.random.default_rng

      numpy.random.shuffle

      numpy.random.Generator.shuffle

      numpy.random.standard_cauchy

      numpy.random.Generator.standard_cauchy

      numpy.random.standard_exponential

      numpy.random.Generator.standard_exponential

      numpy.random.standard_gamma

      numpy.random.Generator.standard_gamma

      numpy.random.standard_normal

      numpy.random.Generator.standard_normal

      numpy.random.standard_t

      numpy.random.Generator.standard_t

      numpy.random.triangular

      numpy.random.Generator.triangular

      numpy.random.uniform

      numpy.random.Generator.uniform

      numpy.random.vonmises

      numpy.random.Generator.vonmises

      numpy.random.wald

      numpy.random.Generator.wald

      numpy.random.weibull

      numpy.random.Generator.weibull

      numpy.random.zipf

      numpy.random.Generator.zipf

      How to fix it

      To fix this issue, replace usages of numpy.random.RandomState to numpy.random.Generator.

      Code examples

      diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6714.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6714.html index 5b5b514b9e..d80e9b1c73 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6714.html +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6714.html @@ -5,7 +5,7 @@

      Why is this an issue?

      goal. This NumPy array will have a have a data type (dtype) of object and could hold any Python objects.

      One of the characteristics of NumPy arrays is homogeneity, meaning all its elements are of the same type. Creating an array of objects allows the user to create heterogeneous array without raising any errors and creating such an array can lead to bugs further in the program.

      -
      +
       arr = np.array(x**2 for x in range(10))
       
       arr.reshape(1)
      diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6729.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6729.html
      index eec1ab122c..d83a0744de 100644
      --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6729.html
      +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6729.html
      @@ -37,7 +37,7 @@ 

      How to fix it

    Code examples

    Noncompliant code example

    -
    +
     import numpy as np
     
     def bigger_than_two():
    diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6730.json b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6730.json
    index 8133e2a396..61c71e1365 100644
    --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6730.json
    +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S6730.json
    @@ -6,7 +6,10 @@
         "func": "Constant\/Issue",
         "constantCost": "5min"
       },
    -  "tags": [],
    +  "tags": [
    +    "numpy",
    +    "data-science"
    +  ],
       "defaultSeverity": "Major",
       "ruleSpecification": "RSPEC-6730",
       "sqKey": "S6730",
    diff --git a/sonarpedia.json b/sonarpedia.json
    index 8abdf954f9..79fde49fb5 100644
    --- a/sonarpedia.json
    +++ b/sonarpedia.json
    @@ -3,7 +3,7 @@
       "languages": [
         "PY"
       ],
    -  "latest-update": "2023-08-17T11:13:24.565991160Z",
    +  "latest-update": "2023-09-25T08:37:06.879611Z",
       "options": {
         "no-language-in-filenames": true,
         "preserve-filenames": true