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[] 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[] 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 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[]