From c99ad72c75f0aa3ff87c55e31cfdc20dc8a5ec0f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 11:46:24 +0100 Subject: [PATCH 1/4] Create go rule S5542: Encryption algorithms should be used with secure mode and padding scheme (#4631) * Add go to rule S5542 * SONARGO-136: Add S5542 for Go * Improvements based on review --------- Co-authored-by: daniel-teuchert-sonarsource Co-authored-by: Daniel Teuchert Co-authored-by: daniel-teuchert-sonarsource <141642369+daniel-teuchert-sonarsource@users.noreply.github.com> --- rules/S5542/go/metadata.json | 2 + rules/S5542/go/rule.adoc | 153 +++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 rules/S5542/go/metadata.json create mode 100644 rules/S5542/go/rule.adoc diff --git a/rules/S5542/go/metadata.json b/rules/S5542/go/metadata.json new file mode 100644 index 00000000000..7a73a41bfdf --- /dev/null +++ b/rules/S5542/go/metadata.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/rules/S5542/go/rule.adoc b/rules/S5542/go/rule.adoc new file mode 100644 index 00000000000..9819e141900 --- /dev/null +++ b/rules/S5542/go/rule.adoc @@ -0,0 +1,153 @@ + +include::../summary.adoc[] + +== Why is this an issue? + +include::../rationale.adoc[] + +include::../impact.adoc[] + +// How to fix it section + +== How to fix it + +=== Code examples + +==== Noncompliant code example + +Example with a symmetric cipher, AES in CBC mode: + +[source,go,diff-id=1,diff-type=noncompliant] +---- +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" +) +func encrypt() { + plaintext := []byte("Exampleplaintext") + + key := make([]byte, 32) + rand.Read(key) + block, _ := aes.NewCipher(key) + iv := make([]byte, block.BlockSize()) + rand.Read(iv) + + encrypter := cipher.NewCBCEncrypter(block, iv) // Noncompliant + + ciphertext := make([]byte, len(plaintext)) + encrypter.CryptBlocks(ciphertext, plaintext) +} +---- + +The following example shows the function `cipher.Block.Encrypt` being used directly to run AES in a self-build ECB mode: + +[source,go] +---- +import ( + "crypto/aes" + "crypto/rand" +) +func encrypt() { + plaintext := []byte("Exampleplaintext") + + key := make([]byte, 32) + rand.Read(key) + block, _ := aes.NewCipher(key) + + ciphertext := make([]byte, len(plaintext)) + block.Encrypt(ciphertext, plaintext) // Noncompliant +} +---- + +Example with an asymetric cipher, RSA with PKCS1v15 padding: + +[source,go,diff-id=2,diff-type=noncompliant] +---- +import ( + "crypto/rand" + "crypto/rsa" +) +func encrypt() { + random := rand.Reader + plaintext := []byte("Exampleplaintext") + privateKey, _ := rsa.GenerateKey(random, 4096) + ciphertext, _ := rsa.EncryptPKCS1v15(random, &privateKey.PublicKey, plaintext) // Noncompliant +} +---- + +==== Compliant solution + +include::../common/fix/aes-compliant-example.adoc[] + +[source,go,diff-id=1,diff-type=compliant] +---- +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" +) +func encrypt() { + plaintext := []byte("Exampleplaintext") + + key := make([]byte, 32) + rand.Read(key) + block, _ := aes.NewCipher(key) + nonce := make([]byte, 12) + rand.Read(nonce) + + aesgcm, _ := cipher.NewGCM(block) + + ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil) +} +---- + +include::../common/fix/rsa-compliant-example.adoc[] + +[source,go,diff-id=2,diff-type=compliant] +---- +import ( + "crypto/rand" + "crypto/rsa" + "crypto/sha256" +) +func encrypt() { + random := rand.Reader + plaintext := []byte("Exampleplaintext") + privateKey, _ := rsa.GenerateKey(random, 4096) + ciphertext, _ := rsa.EncryptOAEP(sha256.New(), random, &privateKey.PublicKey, plaintext, nil) +} +---- + +=== How does this work? + +include::../common/fix/fix.adoc[] + + + +== Resources + +include::../common/resources/docs.adoc[] + +include::../common/resources/articles.adoc[] + +include::../common/resources/presentations.adoc[] + +include::../common/resources/standards.adoc[] + + +ifdef::env-github,rspecator-view[] + +''' +== Implementation Specification +(visible only on this page) + +include::../message.adoc[] + +''' +== Comments And Links +(visible only on this page) + +include::../comments-and-links.adoc[] + +endif::env-github,rspecator-view[] From c1a6b0f5f5e1c17263aeeee975255b97c18970ed Mon Sep 17 00:00:00 2001 From: daniel-teuchert-sonarsource <141642369+daniel-teuchert-sonarsource@users.noreply.github.com> Date: Mon, 3 Feb 2025 11:57:51 +0100 Subject: [PATCH 2/4] Modify rule S4036: Fix Code Example (#4640) --- rules/S4036/go/rule.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/S4036/go/rule.adoc b/rules/S4036/go/rule.adoc index 320c50b4066..6232316b515 100644 --- a/rules/S4036/go/rule.adoc +++ b/rules/S4036/go/rule.adoc @@ -15,7 +15,7 @@ out, _ := exec.Command("ls").CombinedOutput() // Sensitive [source,go] ---- -out, _ := exec.Command("/bin/ls").CombinedOutput() // Compliant +out, _ := exec.Command("/bin/ls").CombinedOutput() ---- include::../see.adoc[] From fc7ed69d884ec7a961fafead87c848c03ea99f40 Mon Sep 17 00:00:00 2001 From: daniel-teuchert-sonarsource <141642369+daniel-teuchert-sonarsource@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:04:32 +0100 Subject: [PATCH 3/4] Add support for aiohttp (#3409) --- rules/S5144/python/how-to-fix-it/aiohttp.adoc | 50 +++++++++++++++++++ rules/S5144/python/rule.adoc | 2 + 2 files changed, 52 insertions(+) create mode 100644 rules/S5144/python/how-to-fix-it/aiohttp.adoc diff --git a/rules/S5144/python/how-to-fix-it/aiohttp.adoc b/rules/S5144/python/how-to-fix-it/aiohttp.adoc new file mode 100644 index 00000000000..dec6e3d7fbf --- /dev/null +++ b/rules/S5144/python/how-to-fix-it/aiohttp.adoc @@ -0,0 +1,50 @@ +== How to fix it in aiohttp + +=== Code examples + +include::../../common/fix/code-rationale.adoc[] + +==== Noncompliant code example + +[source,python,diff-id=31,diff-type=noncompliant] +---- +from fastapi import FastAPI +import aiohttp + +app = FastAPI() +@app.get('/example') +async def example(url: str): + async with aiohttp.request('GET', url) as response: # Noncompliant + return {"response": await response.text()} +---- + +==== Compliant solution + +[source,python,diff-id=31,diff-type=compliant] +---- +from fastapi import FastAPI +from fastapi.responses import JSONResponse +import aiohttp +from urllib.parse import urlparse + +DOMAINS_ALLOWLIST = ['trusted1.example.com', 'trusted2.example.com']; +app = FastAPI() + +@app.get('/example') +async def example(url: str): + if urlparse(url).hostname not in DOMAINS_ALLOWLIST: + return JSONResponse({"error": f"URL {url} is not whitelisted."}, 400) + + async with aiohttp.request('GET', url.unicode_string()) as response: + return {"response": await response.text()} +---- + +=== How does this work? + +include::../../common/fix/pre-approved-list.adoc[] + +The compliant code example uses such an approach. + +=== Pitfalls + +include::../../common/pitfalls/starts-with.adoc[] diff --git a/rules/S5144/python/rule.adoc b/rules/S5144/python/rule.adoc index a359bcb07c4..2c1bfb2dcbb 100644 --- a/rules/S5144/python/rule.adoc +++ b/rules/S5144/python/rule.adoc @@ -10,6 +10,8 @@ include::how-to-fix-it/python.adoc[] include::how-to-fix-it/requests.adoc[] +include::how-to-fix-it/aiohttp.adoc[] + include::how-to-fix-it/httpx.adoc[] == Resources From 071e229c14acd1c2fde16107962f2493761971ad Mon Sep 17 00:00:00 2001 From: daniel-teuchert-sonarsource <141642369+daniel-teuchert-sonarsource@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:08:40 +0100 Subject: [PATCH 4/4] Modify rule S4507: Add support for Flask-GraphQL (#3428) * Added how to fix it section for flask-graphql * Restructured code examples * Adjusted format * Change to allowed_framework_names not needed anymore * Update rule.adoc * Applied suggestion. --- rules/S4507/python/rule.adoc | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/rules/S4507/python/rule.adoc b/rules/S4507/python/rule.adoc index d65c5661365..e2b1825c8e6 100644 --- a/rules/S4507/python/rule.adoc +++ b/rules/S4507/python/rule.adoc @@ -28,6 +28,7 @@ DEBUG = True # Sensitive DEBUG_PROPAGATE_EXCEPTIONS = True # Sensitive ---- + Flask application startup: [source,python,diff-id=3,diff-type=noncompliant] @@ -39,6 +40,25 @@ app.debug = True # Sensitive app.run(debug=True) # Sensitive ---- +The following code defines a GraphQL endpoint with GraphiQL enabled. While this might be a useful configuration during development, it should never be enabled for applications deployed in production: + +[source,python,diff-id=4,diff-type=noncompliant] +---- +from flask import Flask +from graphql_server.flask import GraphQLView + +app = Flask(__name__) + +app.add_url_rule( + '/graphql', + view_func=GraphQLView.as_view( + 'graphql', + schema=schema, + graphiql=True # Sensitive + ) +) +---- + == Compliant Solution [source,python,diff-id=1,diff-type=compliant] @@ -67,6 +87,22 @@ app.debug = False app.run(debug=False) ---- +[source,python,diff-id=4,diff-type=compliant] +---- +from flask import Flask +from graphql_server.flask import GraphQLView + +app = Flask(__name__) + +app.add_url_rule( + '/graphql', + view_func=GraphQLView.as_view( + 'graphql', + schema=schema + ) +) +---- + include::../see.adoc[] ifdef::env-github,rspecator-view[]