Skip to content

Commit

Permalink
Update rule metadata. (#1581)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeremi Do Dinh authored Sep 25, 2023
1 parent 9ceb464 commit 0c49937
Show file tree
Hide file tree
Showing 18 changed files with 601 additions and 233 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<p>Once control flow has been moved out of the current code block, any subsequent statements become effectively unreachable.</p>
<h2>Why is this an issue?</h2>
<p>Jump statements (<code>return</code>, <code>break</code>, <code>continue</code>, and <code>raise</code>) move control flow out of the current code
block. So any statements that come after a jump are dead code.</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,102 @@
<p>When accessing a database, an empty password should be avoided as it introduces a weakness.</p>
<h2>Why is this an issue?</h2>
<p>When relying on the password authentication mode for the database connection, a secure password should be chosen.</p>
<p>This rule raises an issue when an empty password is used.</p>
<h3>Noncompliant code example</h3>
<p>Flask-SQLAlchemy</p>
<pre>
<p>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.</p>
<h3>What is the potential impact?</h3>
<p>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.</p>
<h4>Unauthorized Access to Sensitive Data</h4>
<p>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.</p>
<h4>Compromise of System Integrity</h4>
<p>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.</p>
<h4>Unwanted Modifications or Deletions</h4>
<p>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.</p>
<p>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.</p>
<h2>How to fix it in MySQL Connector/Python</h2>
<h3>Code examples</h3>
<p>The following code uses an empty password to connect to a MySQL database.</p>
<p>The vulnerability can be fixed by using a strong password retrieved from an environment variable <code>DB_PASSWORD</code>. This environment
variable is set during deployment. It should be strong and different for each database.</p>
<h4>Noncompliant code example</h4>
<pre data-diff-id="101" data-diff-type="noncompliant">
from mysql.connector import connection

connection.MySQLConnection(host='localhost', user='sonarsource', password='') # Noncompliant
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="101" data-diff-type="compliant">
from mysql.connector import connection
import os

db_password = os.getenv('DB_PASSWORD')
connection.MySQLConnection(host='localhost', user='sonarsource', password=db_password)
</pre>
<h3>Pitfalls</h3>
<h4>Hard-coded passwords</h4>
<p>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:</p>
<ol>
<li> 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. </li>
<li> 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. </li>
<li> 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. </li>
</ol>
<p>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.</p>
<h2>How to fix it in SQLAlchemy</h2>
<h3>Code examples</h3>
<p>The following code uses an empty password to connect to a Postgres database.</p>
<p>The vulnerability can be fixed by using a strong password retrieved from an environment variable <code>DB_PASSWORD</code>. This environment
variable is set during deployment. It should be strong and different for each database.</p>
<h4>Noncompliant code example</h4>
<pre data-diff-id="103" data-diff-type="noncompliant">
def configure_app(app):
app.config['SQLALCHEMY_DATABASE_URI'] = "postgresql://user:@domain.com" # Noncompliant
</pre>
<p>Django</p>
<pre>
<h4>Compliant solution</h4>
<pre data-diff-id="103" data-diff-type="compliant">
def configure_app(app):
db_password = os.getenv('DB_PASSWORD')
app.config['SQLALCHEMY_DATABASE_URI'] = f"postgresql://user:{db_password}@domain.com"
</pre>
<h3>Pitfalls</h3>
<h4>Hard-coded passwords</h4>
<p>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:</p>
<ol>
<li> 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. </li>
<li> 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. </li>
<li> 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. </li>
</ol>
<p>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.</p>
<h2>How to fix it in Django</h2>
<h3>Code examples</h3>
<p>The following code uses an empty password to connect to a Postgres database.</p>
<p>The vulnerability can be fixed by using a strong password retrieved from an environment variable <code>DB_PASSWORD</code>. This environment
variable is set during deployment. It should be strong and different for each database.</p>
<h4>Noncompliant code example</h4>
<pre data-diff-id="102" data-diff-type="noncompliant">
# settings.py

DATABASES = {
Expand All @@ -22,20 +110,8 @@ <h3>Noncompliant code example</h3>
}
}
</pre>
<p>mysql/mysql-connector-python</p>
<pre>
from mysql.connector import connection

connection.MySQLConnection(host='localhost', user='sonarsource', password='') # Noncompliant
</pre>
<h3>Compliant solution</h3>
<p>Flask-SQLAlchemy</p>
<pre>
def configure_app(app, pwd):
app.config['SQLALCHEMY_DATABASE_URI'] = f"postgresql://user:{pwd}@domain.com" # Compliant
</pre>
<p>Django</p>
<pre>
<h4>Compliant solution</h4>
<pre data-diff-id="102" data-diff-type="compliant">
# settings.py
import os

Expand All @@ -44,21 +120,29 @@ <h3>Compliant solution</h3>
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'quickdb',
'USER': 'sonarsource',
'PASSWORD': os.getenv('DB_PASSWORD'), # Compliant
'PASSWORD': os.getenv('DB_PASSWORD'),
'HOST': 'localhost',
'PORT': '5432'
}
}
</pre>
<p>mysql/mysql-connector-python</p>
<pre>
from mysql.connector import connection
import os

db_password = os.getenv('DB_PASSWORD')
connection.MySQLConnection(host='localhost', user='sonarsource', password=db_password) # Compliant
</pre>
<h3>Pitfalls</h3>
<h4>Hard-coded passwords</h4>
<p>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:</p>
<ol>
<li> 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. </li>
<li> 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. </li>
<li> 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. </li>
</ol>
<p>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.</p>
<h2>Resources</h2>
<h3>Standards</h3>
<ul>
<li> <a href="https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures/">OWASP Top 10 2021 Category A7</a> - Identification and
Authentication Failures </li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"impacts": {
"SECURITY": "HIGH"
},
"attribute": "COMPLETE"
"attribute": "TRUSTWORTHY"
},
"status": "ready",
"remediation": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ <h3>Code examples</h3>
<p>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.</p>
<h4>Noncompliant code example</h4>
<pre data-diff-id="1" data-diff-type="noncompliant">
<pre data-diff-id="11" data-diff-type="noncompliant">
import xml.sax

parser = xml.sax.make_parser()
Expand All @@ -33,7 +33,7 @@ <h4>Noncompliant code example</h4>
</pre>
<h4>Compliant solution</h4>
<p>The SAX parser does not process general external entities by default since version 3.7.1.</p>
<pre data-diff-id="1" data-diff-type="compliant">
<pre data-diff-id="11" data-diff-type="compliant">
import xml.sax

parser = xml.sax.make_parser()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,18 @@ <h4>Compliant solution</h4>
</pre>
<h3>How does this work?</h3>
<h4>Use unique IVs</h4>
<p>To ensure strong security, the initialization vectors for each encryption operation must be unique and random but they do not have to be
secret.</p>
<p>To ensure high security, initialization vectors must meet two important criteria:</p>
<ul>
<li> IVs must be unique for each encryption operation. </li>
<li> For CBC and CFB modes, a secure FIPS-compliant random number generator should be used to generate unpredictable IVs. </li>
</ul>
<p>The IV does not need be secret, so the IV or information sufficient to determine the IV may be transmitted along with the ciphertext.</p>
<p>In the previous non-compliant example, the problem is not that the IV is hard-coded.<br> It is that the same IV is used for multiple encryption
attempts.</p>
<h2>How to fix it in Cryptodome</h2>
<h3>Code examples</h3>
<h4>Noncompliant code example</h4>
<pre data-diff-id="1" data-diff-type="noncompliant">
<pre data-diff-id="11" data-diff-type="noncompliant">
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad
Expand All @@ -85,7 +89,7 @@ <h4>Noncompliant code example</h4>
</pre>
<h4>Compliant solution</h4>
<p>In this example, the code explicitly uses a number generator that is considered <strong>strong</strong>.</p>
<pre data-diff-id="1" data-diff-type="compliant">
<pre data-diff-id="11" data-diff-type="compliant">
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad
Expand All @@ -96,8 +100,12 @@ <h4>Compliant solution</h4>
</pre>
<h3>How does this work?</h3>
<h4>Use unique IVs</h4>
<p>To ensure strong security, the initialization vectors for each encryption operation must be unique and random but they do not have to be
secret.</p>
<p>To ensure high security, initialization vectors must meet two important criteria:</p>
<ul>
<li> IVs must be unique for each encryption operation. </li>
<li> For CBC and CFB modes, a secure FIPS-compliant random number generator should be used to generate unpredictable IVs. </li>
</ul>
<p>The IV does not need be secret, so the IV or information sufficient to determine the IV may be transmitted along with the ciphertext.</p>
<p>In the previous non-compliant example, the problem is not that the IV is hard-coded.<br> It is that the same IV is used for multiple encryption
attempts.</p>
<h2>Resources</h2>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ <h4>Legal and compliance issues</h4>
<h2>How to fix it in Python Standard Library</h2>
<h3>Code examples</h3>
<h4>Noncompliant code example</h4>
<pre data-diff-id="1" data-diff-type="noncompliant">
<pre data-diff-id="21" data-diff-type="noncompliant">
import ssl

ssl.SSLContext(ssl.PROTOCOL_SSLv3) # Noncompliant
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="1" data-diff-type="compliant">
<pre data-diff-id="21" data-diff-type="compliant">
import ssl

context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
Expand All @@ -70,13 +70,13 @@ <h4>Use TLS v1.2 or TLS v1.3</h4>
<h2>How to fix it in OpenSSL</h2>
<h3>Code examples</h3>
<h4>Noncompliant code example</h4>
<pre data-diff-id="1" data-diff-type="noncompliant">
<pre data-diff-id="11" data-diff-type="noncompliant">
from OpenSSL import SSL

SSL.Context(SSL.SSLv3_METHOD) # Noncompliant
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="1" data-diff-type="compliant">
<pre data-diff-id="11" data-diff-type="compliant">
from OpenSSL import SSL

context = SSL.Context(SSL.TLS_SERVER_METHOD)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ <h3>Code examples</h3>
<p>Certificate validation is not enabled by default when <code>_create_unverified_context</code> is used. It is recommended to use
<code>_create_default_https_context</code> instead to create a secure context that validates certificates.</p>
<h4>Noncompliant code example</h4>
<pre data-diff-id="1" data-diff-type="noncompliant">
<pre data-diff-id="21" data-diff-type="noncompliant">
import ssl

ctx1 = ssl._create_unverified_context() # Noncompliant
Expand All @@ -34,7 +34,7 @@ <h4>Noncompliant code example</h4>
ctx3.verify_mode = ssl.CERT_NONE # Noncompliant
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="1" data-diff-type="compliant">
<pre data-diff-id="21" data-diff-type="compliant">
import ssl

ctx = ssl.create_default_context()
Expand Down Expand Up @@ -67,7 +67,7 @@ <h4>Noncompliant code example</h4>
ctx2.set_verify(SSL.VERIFY_NONE, verify_callback) # Noncompliant
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="1" data-diff-type="noncompliant">
<pre data-diff-id="1" data-diff-type="compliant">
from OpenSSL import SSL

ctx = SSL.Context(SSL.TLSv1_2_METHOD)
Expand All @@ -91,13 +91,13 @@ <h3>Code examples</h3>
<p>The certificate validation gets disabled by setting <code>verify</code> to <code>False</code>. To enable validation set the value to
<code>True</code> or do not set <code>verify</code> at all to use the secure default value.</p>
<h4>Noncompliant code example</h4>
<pre data-diff-id="1" data-diff-type="noncompliant">
<pre data-diff-id="11" data-diff-type="noncompliant">
import requests

requests.request('GET', 'https://example.com', verify=False) # Noncompliant
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="1" data-diff-type="noncompliant">
<pre data-diff-id="11" data-diff-type="compliant">
import requests

# By default, certificate validation is enabled
Expand Down
Loading

0 comments on commit 0c49937

Please sign in to comment.