83 lines
2.6 KiB
Plaintext
83 lines
2.6 KiB
Plaintext
![]() |
== 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[]
|
||
|
|