Modify rule S5131: Add FastAPI (APPSEC-1250) (#3412)
This commit is contained in:
parent
6a8c878999
commit
6fe3e11073
@ -79,6 +79,7 @@
|
||||
* Django Templates
|
||||
* Flask
|
||||
* aiohttp
|
||||
* FastAPI
|
||||
* Jinja
|
||||
* lxml
|
||||
* Paramiko
|
||||
|
82
rules/S5131/python/how-to-fix-it/fastapi.adoc
Normal file
82
rules/S5131/python/how-to-fix-it/fastapi.adoc
Normal file
@ -0,0 +1,82 @@
|
||||
== How to fix it in FastAPI
|
||||
|
||||
=== Code examples
|
||||
|
||||
The following code is vulnerable to cross-site scripting because it returns an HTML response that contains user input.
|
||||
|
||||
If you do not intend to send HTML code to clients, the vulnerability can be fixed by specifying the type of data returned in the response.
|
||||
For example, you can use the `JsonResponse` class to return JSON messages securely.
|
||||
|
||||
It is also possible to set the `Content-Type` manually by using the `media_type` parameter of the `Response` constructor.
|
||||
|
||||
==== Noncompliant code example
|
||||
|
||||
[source,python,diff-id=41,diff-type=noncompliant]
|
||||
----
|
||||
from fastapi import FastAPI, Response
|
||||
import json
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get("/example")
|
||||
def example(input: str):
|
||||
json_str = json.dumps({"data": input})
|
||||
return Response(json_str) # Noncompliant
|
||||
----
|
||||
|
||||
[source,python,diff-id=42,diff-type=noncompliant]
|
||||
----
|
||||
from fastapi import FastAPI, Response
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get("/example")
|
||||
def example(input: str):
|
||||
return Response(input) # Noncompliant
|
||||
----
|
||||
|
||||
==== Compliant solution
|
||||
|
||||
[source,python,diff-id=41,diff-type=compliant]
|
||||
----
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get("/example")
|
||||
def example(input: str):
|
||||
return JSONResponse({"data": input})
|
||||
----
|
||||
|
||||
[source,python,diff-id=42,diff-type=compliant]
|
||||
----
|
||||
from fastapi import FastAPI, Response
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get("/example")
|
||||
def example(input: str):
|
||||
return Response(input, media_type="text/plain")
|
||||
----
|
||||
|
||||
=== How does this work?
|
||||
|
||||
If the HTTP response is HTML code, it is highly recommended to use a template engine like https://jinja.palletsprojects.com/[Jinja] to generate it.
|
||||
This template engine separates the view from the business logic and automatically encodes the output of variables, drastically reducing the risk of cross-site scripting vulnerabilities.
|
||||
|
||||
If you do not intend to send HTML code to clients, the vulnerability can be fixed by correctly setting the `Content-Type` HTTP header.
|
||||
This HTTP header defines which media type the browser can expect from the response, so the browser can parse it correctly. By specifying a type that is not HTML, the browser does not interpret the response as HTML, which in turn prevents cross-site scripting.
|
||||
|
||||
For example, when setting the `Content-Type` header to `text/plain`, browsers will interpret the HTTP response as plaintext and will not process it any further. This allows user input to be reflected safely.
|
||||
|
||||
=== Pitfalls
|
||||
|
||||
include::../../common/pitfalls/content-types.adoc[]
|
||||
|
||||
include::../../common/pitfalls/validation.adoc[]
|
||||
|
||||
=== Going the extra mile
|
||||
|
||||
include::../../common/extra-mile/csp.adoc[]
|
||||
|
@ -16,6 +16,8 @@ include::how-to-fix-it/flask.adoc[]
|
||||
|
||||
include::how-to-fix-it/jinja.adoc[]
|
||||
|
||||
include::how-to-fix-it/fastapi.adoc[]
|
||||
|
||||
== Resources
|
||||
|
||||
include::../common/resources/docs.adoc[]
|
||||
|
Loading…
x
Reference in New Issue
Block a user