Skip to content

Commit

Permalink
Merge branch 'master' into rule/add-RSPEC-S7197
Browse files Browse the repository at this point in the history
  • Loading branch information
zglicz authored Feb 3, 2025
2 parents fc7ec2f + 071e229 commit 86fde28
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 1 deletion.
2 changes: 1 addition & 1 deletion rules/S4036/go/rule.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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[]
Expand Down
36 changes: 36 additions & 0 deletions rules/S4507/python/rule.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ DEBUG = True # Sensitive
DEBUG_PROPAGATE_EXCEPTIONS = True # Sensitive
----


Flask application startup:

[source,python,diff-id=3,diff-type=noncompliant]
Expand All @@ -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]
Expand Down Expand Up @@ -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[]
Expand Down
50 changes: 50 additions & 0 deletions rules/S5144/python/how-to-fix-it/aiohttp.adoc
Original file line number Diff line number Diff line change
@@ -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[]
2 changes: 2 additions & 0 deletions rules/S5144/python/rule.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions rules/S5542/go/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
153 changes: 153 additions & 0 deletions rules/S5542/go/rule.adoc
Original file line number Diff line number Diff line change
@@ -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[]

0 comments on commit 86fde28

Please sign in to comment.