Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoSign in
Socket

flask

Package Overview
Dependencies
Maintainers
0
Versions
64
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

flask - pypi Package Compare versions

Comparing version
3.0.2
to
3.0.3
+274
docs/web-security.rst
Security Considerations
=======================
Web applications usually face all kinds of security problems and it's very
hard to get everything right. Flask tries to solve a few of these things
for you, but there are a couple more you have to take care of yourself.
.. _security-xss:
Cross-Site Scripting (XSS)
--------------------------
Cross site scripting is the concept of injecting arbitrary HTML (and with
it JavaScript) into the context of a website. To remedy this, developers
have to properly escape text so that it cannot include arbitrary HTML
tags. For more information on that have a look at the Wikipedia article
on `Cross-Site Scripting
<https://en.wikipedia.org/wiki/Cross-site_scripting>`_.
Flask configures Jinja2 to automatically escape all values unless
explicitly told otherwise. This should rule out all XSS problems caused
in templates, but there are still other places where you have to be
careful:
- generating HTML without the help of Jinja2
- calling :class:`~markupsafe.Markup` on data submitted by users
- sending out HTML from uploaded files, never do that, use the
``Content-Disposition: attachment`` header to prevent that problem.
- sending out textfiles from uploaded files. Some browsers are using
content-type guessing based on the first few bytes so users could
trick a browser to execute HTML.
Another thing that is very important are unquoted attributes. While
Jinja2 can protect you from XSS issues by escaping HTML, there is one
thing it cannot protect you from: XSS by attribute injection. To counter
this possible attack vector, be sure to always quote your attributes with
either double or single quotes when using Jinja expressions in them:
.. sourcecode:: html+jinja
<input value="{{ value }}">
Why is this necessary? Because if you would not be doing that, an
attacker could easily inject custom JavaScript handlers. For example an
attacker could inject this piece of HTML+JavaScript:
.. sourcecode:: html
onmouseover=alert(document.cookie)
When the user would then move with the mouse over the input, the cookie
would be presented to the user in an alert window. But instead of showing
the cookie to the user, a good attacker might also execute any other
JavaScript code. In combination with CSS injections the attacker might
even make the element fill out the entire page so that the user would
just have to have the mouse anywhere on the page to trigger the attack.
There is one class of XSS issues that Jinja's escaping does not protect
against. The ``a`` tag's ``href`` attribute can contain a `javascript:` URI,
which the browser will execute when clicked if not secured properly.
.. sourcecode:: html
<a href="{{ value }}">click here</a>
<a href="javascript:alert('unsafe');">click here</a>
To prevent this, you'll need to set the :ref:`security-csp` response header.
Cross-Site Request Forgery (CSRF)
---------------------------------
Another big problem is CSRF. This is a very complex topic and I won't
outline it here in detail just mention what it is and how to theoretically
prevent it.
If your authentication information is stored in cookies, you have implicit
state management. The state of "being logged in" is controlled by a
cookie, and that cookie is sent with each request to a page.
Unfortunately that includes requests triggered by 3rd party sites. If you
don't keep that in mind, some people might be able to trick your
application's users with social engineering to do stupid things without
them knowing.
Say you have a specific URL that, when you sent ``POST`` requests to will
delete a user's profile (say ``http://example.com/user/delete``). If an
attacker now creates a page that sends a post request to that page with
some JavaScript they just have to trick some users to load that page and
their profiles will end up being deleted.
Imagine you were to run Facebook with millions of concurrent users and
someone would send out links to images of little kittens. When users
would go to that page, their profiles would get deleted while they are
looking at images of fluffy cats.
How can you prevent that? Basically for each request that modifies
content on the server you would have to either use a one-time token and
store that in the cookie **and** also transmit it with the form data.
After receiving the data on the server again, you would then have to
compare the two tokens and ensure they are equal.
Why does Flask not do that for you? The ideal place for this to happen is
the form validation framework, which does not exist in Flask.
.. _security-json:
JSON Security
-------------
In Flask 0.10 and lower, :func:`~flask.jsonify` did not serialize top-level
arrays to JSON. This was because of a security vulnerability in ECMAScript 4.
ECMAScript 5 closed this vulnerability, so only extremely old browsers are
still vulnerable. All of these browsers have `other more serious
vulnerabilities
<https://github.com/pallets/flask/issues/248#issuecomment-59934857>`_, so
this behavior was changed and :func:`~flask.jsonify` now supports serializing
arrays.
Security Headers
----------------
Browsers recognize various response headers in order to control security. We
recommend reviewing each of the headers below for use in your application.
The `Flask-Talisman`_ extension can be used to manage HTTPS and the security
headers for you.
.. _Flask-Talisman: https://github.com/GoogleCloudPlatform/flask-talisman
HTTP Strict Transport Security (HSTS)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the browser to convert all HTTP requests to HTTPS, preventing
man-in-the-middle (MITM) attacks. ::
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
.. _security-csp:
Content Security Policy (CSP)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tell the browser where it can load various types of resource from. This header
should be used whenever possible, but requires some work to define the correct
policy for your site. A very strict policy would be::
response.headers['Content-Security-Policy'] = "default-src 'self'"
- https://csp.withgoogle.com/docs/index.html
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
X-Content-Type-Options
~~~~~~~~~~~~~~~~~~~~~~
Forces the browser to honor the response content type instead of trying to
detect it, which can be abused to generate a cross-site scripting (XSS)
attack. ::
response.headers['X-Content-Type-Options'] = 'nosniff'
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
X-Frame-Options
~~~~~~~~~~~~~~~
Prevents external sites from embedding your site in an ``iframe``. This
prevents a class of attacks where clicks in the outer frame can be translated
invisibly to clicks on your page's elements. This is also known as
"clickjacking". ::
response.headers['X-Frame-Options'] = 'SAMEORIGIN'
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
.. _security-cookie:
Set-Cookie options
~~~~~~~~~~~~~~~~~~
These options can be added to a ``Set-Cookie`` header to improve their
security. Flask has configuration options to set these on the session cookie.
They can be set on other cookies too.
- ``Secure`` limits cookies to HTTPS traffic only.
- ``HttpOnly`` protects the contents of cookies from being read with
JavaScript.
- ``SameSite`` restricts how cookies are sent with requests from
external sites. Can be set to ``'Lax'`` (recommended) or ``'Strict'``.
``Lax`` prevents sending cookies with CSRF-prone requests from
external sites, such as submitting a form. ``Strict`` prevents sending
cookies with all external requests, including following regular links.
::
app.config.update(
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE='Lax',
)
response.set_cookie('username', 'flask', secure=True, httponly=True, samesite='Lax')
Specifying ``Expires`` or ``Max-Age`` options, will remove the cookie after
the given time, or the current time plus the age, respectively. If neither
option is set, the cookie will be removed when the browser is closed. ::
# cookie expires after 10 minutes
response.set_cookie('snakes', '3', max_age=600)
For the session cookie, if :attr:`session.permanent <flask.session.permanent>`
is set, then :data:`PERMANENT_SESSION_LIFETIME` is used to set the expiration.
Flask's default cookie implementation validates that the cryptographic
signature is not older than this value. Lowering this value may help mitigate
replay attacks, where intercepted cookies can be sent at a later time. ::
app.config.update(
PERMANENT_SESSION_LIFETIME=600
)
@app.route('/login', methods=['POST'])
def login():
...
session.clear()
session['user_id'] = user.id
session.permanent = True
...
Use :class:`itsdangerous.TimedSerializer` to sign and validate other cookie
values (or any values that need secure signatures).
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
.. _samesite_support: https://caniuse.com/#feat=same-site-cookie-attribute
HTTP Public Key Pinning (HPKP)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This tells the browser to authenticate with the server using only the specific
certificate key to prevent MITM attacks.
.. warning::
Be careful when enabling this, as it is very difficult to undo if you set up
or upgrade your key incorrectly.
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning
Copy/Paste to Terminal
----------------------
Hidden characters such as the backspace character (``\b``, ``^H``) can
cause text to render differently in HTML than how it is interpreted if
`pasted into a terminal <https://security.stackexchange.com/q/39118>`__.
For example, ``import y\bose\bm\bi\bt\be\b`` renders as
``import yosemite`` in HTML, but the backspaces are applied when pasted
into a terminal, and it becomes ``import os``.
If you expect users to copy and paste untrusted code from your site,
such as from comments posted by users on a technical blog, consider
applying extra filtering, such as replacing all ``\b`` characters.
.. code-block:: python
body = body.replace("\b", "")
Most modern terminals will warn about and remove hidden characters when
pasting, so this isn't strictly necessary. It's also possible to craft
dangerous commands in other ways that aren't possible to filter.
Depending on your site's use case, it may be good to show a warning
about copying code in general.
Copyright 2010 Pallets
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Flask
Flask is a lightweight [WSGI][] web application framework. It is designed
to make getting started quick and easy, with the ability to scale up to
complex applications. It began as a simple wrapper around [Werkzeug][]
and [Jinja][], and has become one of the most popular Python web
application frameworks.
Flask offers suggestions, but doesn't enforce any dependencies or
project layout. It is up to the developer to choose the tools and
libraries they want to use. There are many extensions provided by the
community that make adding new functionality easy.
[WSGI]: https://wsgi.readthedocs.io/
[Werkzeug]: https://werkzeug.palletsprojects.com/
[Jinja]: https://jinja.palletsprojects.com/
## Installing
Install and update from [PyPI][] using an installer such as [pip][]:
```
$ pip install -U Flask
```
[PyPI]: https://pypi.org/project/Flask/
[pip]: https://pip.pypa.io/en/stable/getting-started/
## A Simple Example
```python
# save this as app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World!"
```
```
$ flask run
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
```
## Contributing
For guidance on setting up a development environment and how to make a
contribution to Flask, see the [contributing guidelines][].
[contributing guidelines]: https://github.com/pallets/flask/blob/main/CONTRIBUTING.rst
## Donate
The Pallets organization develops and supports Flask and the libraries
it uses. In order to grow the community of contributors and users, and
allow the maintainers to devote more time to the projects, [please
donate today][].
[please donate today]: https://palletsprojects.com/donate
+9
-8

@@ -14,12 +14,18 @@ import packaging.version

master_doc = "index"
default_role = "code"
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.extlinks",
"sphinx.ext.intersphinx",
"sphinxcontrib.log_cabinet",
"sphinx_tabs.tabs",
"pallets_sphinx_themes",
"sphinx_issues",
"sphinx_tabs.tabs",
]
autodoc_member_order = "bysource"
autodoc_typehints = "description"
autodoc_preserve_defaults = True
extlinks = {
"issue": ("https://github.com/pallets/flask/issues/%s", "#%s"),
"pr": ("https://github.com/pallets/flask/pull/%s", "#%s"),
}
intersphinx_mapping = {

@@ -35,3 +41,2 @@ "python": ("https://docs.python.org/3/", None),

}
issues_github_path = "pallets/flask"

@@ -62,6 +67,2 @@ # HTML -----------------------------------------------------------------

# LaTeX ----------------------------------------------------------------
latex_documents = [(master_doc, f"Flask-{version}.tex", html_title, author, "manual")]
# Local Extensions -----------------------------------------------------

@@ -68,0 +69,0 @@

@@ -57,3 +57,3 @@ .. rst-class:: hide-header

patterns/index
security
web-security
deploying/index

@@ -60,0 +60,0 @@ async-await

BSD-3-Clause License
====================
.. include:: ../LICENSE.rst
.. literalinclude:: ../LICENSE.txt
:language: text

@@ -162,3 +162,3 @@ Logging

for logger in (
app.logger,
logging.getLogger(app.name),
logging.getLogger('sqlalchemy'),

@@ -165,0 +165,0 @@ logging.getLogger('other_package'),

+38
-53
Metadata-Version: 2.1
Name: Flask
Version: 3.0.2
Version: 3.0.3
Summary: A simple framework for building complex web applications.
Maintainer-email: Pallets <contact@palletsprojects.com>
Requires-Python: >=3.8
Description-Content-Type: text/x-rst
Description-Content-Type: text/markdown
Classifier: Development Status :: 5 - Production/Stable

@@ -19,2 +19,3 @@ Classifier: Environment :: Web Environment

Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Typing :: Typed
Requires-Dist: Werkzeug>=3.0.0

@@ -32,14 +33,12 @@ Requires-Dist: Jinja2>=3.1.2

Project-URL: Donate, https://palletsprojects.com/donate
Project-URL: Issue Tracker, https://github.com/pallets/flask/issues/
Project-URL: Source Code, https://github.com/pallets/flask/
Project-URL: Source, https://github.com/pallets/flask/
Provides-Extra: async
Provides-Extra: dotenv
Flask
=====
# Flask
Flask is a lightweight `WSGI`_ web application framework. It is designed
Flask is a lightweight [WSGI][] web application framework. It is designed
to make getting started quick and easy, with the ability to scale up to
complex applications. It began as a simple wrapper around `Werkzeug`_
and `Jinja`_ and has become one of the most popular Python web
complex applications. It began as a simple wrapper around [Werkzeug][]
and [Jinja][], and has become one of the most popular Python web
application frameworks.

@@ -52,68 +51,54 @@

.. _WSGI: https://wsgi.readthedocs.io/
.. _Werkzeug: https://werkzeug.palletsprojects.com/
.. _Jinja: https://jinja.palletsprojects.com/
[WSGI]: https://wsgi.readthedocs.io/
[Werkzeug]: https://werkzeug.palletsprojects.com/
[Jinja]: https://jinja.palletsprojects.com/
Installing
----------
## Installing
Install and update using `pip`_:
Install and update from [PyPI][] using an installer such as [pip][]:
.. code-block:: text
```
$ pip install -U Flask
```
$ pip install -U Flask
[PyPI]: https://pypi.org/project/Flask/
[pip]: https://pip.pypa.io/en/stable/getting-started/
.. _pip: https://pip.pypa.io/en/stable/getting-started/
## A Simple Example
A Simple Example
----------------
```python
# save this as app.py
from flask import Flask
.. code-block:: python
app = Flask(__name__)
# save this as app.py
from flask import Flask
@app.route("/")
def hello():
return "Hello, World!"
```
app = Flask(__name__)
```
$ flask run
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
```
@app.route("/")
def hello():
return "Hello, World!"
.. code-block:: text
## Contributing
$ flask run
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Contributing
------------
For guidance on setting up a development environment and how to make a
contribution to Flask, see the `contributing guidelines`_.
contribution to Flask, see the [contributing guidelines][].
.. _contributing guidelines: https://github.com/pallets/flask/blob/main/CONTRIBUTING.rst
[contributing guidelines]: https://github.com/pallets/flask/blob/main/CONTRIBUTING.rst
Donate
------
## Donate
The Pallets organization develops and supports Flask and the libraries
it uses. In order to grow the community of contributors and users, and
allow the maintainers to devote more time to the projects, `please
donate today`_.
allow the maintainers to devote more time to the projects, [please
donate today][].
.. _please donate today: https://palletsprojects.com/donate
[please donate today]: https://palletsprojects.com/donate
Links
-----
- Documentation: https://flask.palletsprojects.com/
- Changes: https://flask.palletsprojects.com/changes/
- PyPI Releases: https://pypi.org/project/Flask/
- Source Code: https://github.com/pallets/flask/
- Issue Tracker: https://github.com/pallets/flask/issues/
- Chat: https://discord.gg/pallets
[project]
name = "Flask"
version = "3.0.2"
version = "3.0.3"
description = "A simple framework for building complex web applications."
readme = "README.rst"
license = {file = "LICENSE.rst"}
readme = "README.md"
license = {file = "LICENSE.txt"}
maintainers = [{name = "Pallets", email = "contact@palletsprojects.com"}]

@@ -20,2 +20,3 @@ classifiers = [

"Topic :: Software Development :: Libraries :: Application Frameworks",
"Typing :: Typed",
]

@@ -36,4 +37,3 @@ requires-python = ">=3.8"

Changes = "https://flask.palletsprojects.com/changes/"
"Source Code" = "https://github.com/pallets/flask/"
"Issue Tracker" = "https://github.com/pallets/flask/issues/"
Source = "https://github.com/pallets/flask/"
Chat = "https://discord.gg/pallets"

@@ -98,2 +98,7 @@

[tool.pyright]
pythonVersion = "3.8"
include = ["src/flask", "tests"]
typeCheckingMode = "basic"
[tool.ruff]

@@ -103,3 +108,3 @@ src = ["src"]

show-fixes = true
show-source = true
output-format = "full"

@@ -106,0 +111,0 @@ [tool.ruff.lint]

#
# This file is autogenerated by pip-compile with Python 3.11
# This file is autogenerated by pip-compile with Python 3.12
# by the following command:

@@ -7,7 +7,7 @@ #

#
build==1.0.3
build==1.2.1
# via -r build.in
packaging==23.2
packaging==24.0
# via build
pyproject-hooks==1.0.0
# via build

@@ -1,6 +0,5 @@

-r docs.in
-r tests.in
-r typing.in
pip-tools
-r docs.txt
-r tests.txt
-r typing.txt
pre-commit
tox
#
# This file is autogenerated by pip-compile with Python 3.11
# This file is autogenerated by pip-compile with Python 3.12
# by the following command:

@@ -8,17 +8,23 @@ #

alabaster==0.7.16
# via sphinx
asgiref==3.7.2
# via
# -r tests.in
# -r typing.in
# -r docs.txt
# sphinx
asgiref==3.8.1
# via
# -r tests.txt
# -r typing.txt
babel==2.14.0
# via sphinx
build==1.0.3
# via pip-tools
cachetools==5.3.2
# via
# -r docs.txt
# sphinx
cachetools==5.3.3
# via tox
certifi==2023.11.17
# via requests
certifi==2024.2.2
# via
# -r docs.txt
# requests
cffi==1.16.0
# via cryptography
# via
# -r typing.txt
# cryptography
cfgv==3.4.0

@@ -29,40 +35,59 @@ # via pre-commit

charset-normalizer==3.3.2
# via requests
click==8.1.7
# via pip-tools
# via
# -r docs.txt
# requests
colorama==0.4.6
# via tox
cryptography==41.0.7
# via -r typing.in
cryptography==42.0.5
# via -r typing.txt
distlib==0.3.8
# via virtualenv
docutils==0.18.1
docutils==0.20.1
# via
# -r docs.txt
# sphinx
# sphinx-tabs
filelock==3.13.1
filelock==3.13.3
# via
# tox
# virtualenv
identify==2.5.33
identify==2.5.35
# via pre-commit
idna==3.6
# via requests
# via
# -r docs.txt
# requests
imagesize==1.4.1
# via sphinx
# via
# -r docs.txt
# sphinx
iniconfig==2.0.0
# via pytest
# via
# -r tests.txt
# -r typing.txt
# pytest
jinja2==3.1.3
# via sphinx
markupsafe==2.1.3
# via jinja2
mypy==1.8.0
# via -r typing.in
# via
# -r docs.txt
# sphinx
markupsafe==2.1.5
# via
# -r docs.txt
# jinja2
mypy==1.9.0
# via -r typing.txt
mypy-extensions==1.0.0
# via mypy
# via
# -r typing.txt
# mypy
nodeenv==1.8.0
# via pre-commit
packaging==23.2
# via
# build
# -r typing.txt
# pre-commit
# pyright
packaging==24.0
# via
# -r docs.txt
# -r tests.txt
# -r typing.txt
# pallets-sphinx-themes

@@ -74,19 +99,22 @@ # pyproject-api

pallets-sphinx-themes==2.1.1
# via -r docs.in
pip-tools==7.3.0
# via -r dev.in
platformdirs==4.1.0
# via -r docs.txt
platformdirs==4.2.0
# via
# tox
# virtualenv
pluggy==1.3.0
pluggy==1.4.0
# via
# -r tests.txt
# -r typing.txt
# pytest
# tox
pre-commit==3.6.0
pre-commit==3.7.0
# via -r dev.in
pycparser==2.21
# via cffi
pycparser==2.22
# via
# -r typing.txt
# cffi
pygments==2.17.2
# via
# -r docs.txt
# sphinx

@@ -96,60 +124,76 @@ # sphinx-tabs

# via tox
pyproject-hooks==1.0.0
# via build
pytest==7.4.4
# via -r tests.in
python-dotenv==1.0.0
pyright==1.1.357
# via -r typing.txt
pytest==8.1.1
# via
# -r tests.in
# -r typing.in
# -r tests.txt
# -r typing.txt
python-dotenv==1.0.1
# via
# -r tests.txt
# -r typing.txt
pyyaml==6.0.1
# via pre-commit
requests==2.31.0
# via sphinx
# via
# -r docs.txt
# sphinx
snowballstemmer==2.2.0
# via sphinx
# via
# -r docs.txt
# sphinx
sphinx==7.2.6
# via
# -r docs.in
# -r docs.txt
# pallets-sphinx-themes
# sphinx-issues
# sphinx-tabs
# sphinxcontrib-log-cabinet
sphinx-issues==3.0.1
# via -r docs.in
sphinx-tabs==3.4.4
# via -r docs.in
sphinx-tabs==3.4.5
# via -r docs.txt
sphinxcontrib-applehelp==1.0.8
# via sphinx
# via
# -r docs.txt
# sphinx
sphinxcontrib-devhelp==1.0.6
# via sphinx
# via
# -r docs.txt
# sphinx
sphinxcontrib-htmlhelp==2.0.5
# via sphinx
# via
# -r docs.txt
# sphinx
sphinxcontrib-jsmath==1.0.1
# via sphinx
# via
# -r docs.txt
# sphinx
sphinxcontrib-log-cabinet==1.0.1
# via -r docs.in
# via -r docs.txt
sphinxcontrib-qthelp==1.0.7
# via sphinx
# via
# -r docs.txt
# sphinx
sphinxcontrib-serializinghtml==1.1.10
# via sphinx
tox==4.12.0
# via
# -r docs.txt
# sphinx
tox==4.14.2
# via -r dev.in
types-contextvars==2.4.7.3
# via -r typing.in
# via -r typing.txt
types-dataclasses==0.6.6
# via -r typing.in
typing-extensions==4.9.0
# via mypy
urllib3==2.1.0
# via requests
virtualenv==20.25.0
# via -r typing.txt
typing-extensions==4.11.0
# via
# -r typing.txt
# mypy
urllib3==2.2.1
# via
# -r docs.txt
# requests
virtualenv==20.25.1
# via
# pre-commit
# tox
wheel==0.42.0
# via pip-tools
# The following packages are considered to be unsafe in a requirements file:
# pip
# setuptools
pallets-sphinx-themes
sphinx
sphinx-issues
sphinxcontrib-log-cabinet
sphinx-tabs
#
# This file is autogenerated by pip-compile with Python 3.11
# This file is autogenerated by pip-compile with Python 3.12
# by the following command:

@@ -11,7 +11,7 @@ #

# via sphinx
certifi==2023.11.17
certifi==2024.2.2
# via requests
charset-normalizer==3.3.2
# via requests
docutils==0.18.1
docutils==0.20.1
# via

@@ -26,5 +26,5 @@ # sphinx

# via sphinx
markupsafe==2.1.3
markupsafe==2.1.5
# via jinja2
packaging==23.2
packaging==24.0
# via

@@ -47,9 +47,6 @@ # pallets-sphinx-themes

# pallets-sphinx-themes
# sphinx-issues
# sphinx-tabs
# sphinxcontrib-log-cabinet
sphinx-issues==3.0.1
sphinx-tabs==3.4.5
# via -r docs.in
sphinx-tabs==3.4.4
# via -r docs.in
sphinxcontrib-applehelp==1.0.8

@@ -69,3 +66,3 @@ # via sphinx

# via sphinx
urllib3==2.1.0
urllib3==2.2.1
# via requests
#
# This file is autogenerated by pip-compile with Python 3.11
# This file is autogenerated by pip-compile with Python 3.12
# by the following command:

@@ -7,13 +7,13 @@ #

#
asgiref==3.7.2
asgiref==3.8.1
# via -r tests.in
iniconfig==2.0.0
# via pytest
packaging==23.2
packaging==24.0
# via pytest
pluggy==1.3.0
pluggy==1.4.0
# via pytest
pytest==7.4.4
pytest==8.1.1
# via -r tests.in
python-dotenv==1.0.0
python-dotenv==1.0.1
# via -r tests.in
mypy
pyright
pytest
types-contextvars

@@ -3,0 +5,0 @@ types-dataclasses

#
# This file is autogenerated by pip-compile with Python 3.11
# This file is autogenerated by pip-compile with Python 3.12
# by the following command:

@@ -7,16 +7,28 @@ #

#
asgiref==3.7.2
asgiref==3.8.1
# via -r typing.in
cffi==1.16.0
# via cryptography
cryptography==41.0.7
cryptography==42.0.5
# via -r typing.in
mypy==1.8.0
iniconfig==2.0.0
# via pytest
mypy==1.9.0
# via -r typing.in
mypy-extensions==1.0.0
# via mypy
pycparser==2.21
nodeenv==1.8.0
# via pyright
packaging==24.0
# via pytest
pluggy==1.4.0
# via pytest
pycparser==2.22
# via cffi
python-dotenv==1.0.0
pyright==1.1.357
# via -r typing.in
pytest==8.1.1
# via -r typing.in
python-dotenv==1.0.1
# via -r typing.in
types-contextvars==2.4.7.3

@@ -26,3 +38,6 @@ # via -r typing.in

# via -r typing.in
typing-extensions==4.9.0
typing-extensions==4.11.0
# via mypy
# The following packages are considered to be unsafe in a requirements file:
# setuptools

@@ -244,2 +244,12 @@ from __future__ import annotations

#: The Click command group for registering CLI commands for this
#: object. The commands are available from the ``flask`` command
#: once the application has been discovered and blueprints have
#: been registered.
self.cli = cli.AppGroup()
# Set the name of the Click group in case someone wants to add
# the app's commands to another CLI tool.
self.cli.name = self.name
# Add a static route using the provided static_url_path, static_host,

@@ -246,0 +256,0 @@ # and static_folder if there is a configured static_folder.

@@ -7,2 +7,3 @@ from __future__ import annotations

from .cli import AppGroup
from .globals import current_app

@@ -12,2 +13,3 @@ from .helpers import send_from_directory

from .sansio.blueprints import BlueprintSetupState as BlueprintSetupState # noqa
from .sansio.scaffold import _sentinel

@@ -19,2 +21,38 @@ if t.TYPE_CHECKING: # pragma: no cover

class Blueprint(SansioBlueprint):
def __init__(
self,
name: str,
import_name: str,
static_folder: str | os.PathLike[str] | None = None,
static_url_path: str | None = None,
template_folder: str | os.PathLike[str] | None = None,
url_prefix: str | None = None,
subdomain: str | None = None,
url_defaults: dict[str, t.Any] | None = None,
root_path: str | None = None,
cli_group: str | None = _sentinel, # type: ignore
) -> None:
super().__init__(
name,
import_name,
static_folder,
static_url_path,
template_folder,
url_prefix,
subdomain,
url_defaults,
root_path,
cli_group,
)
#: The Click command group for registering CLI commands for this
#: object. The commands are available from the ``flask`` command
#: once the application has been discovered and blueprints have
#: been registered.
self.cli = AppGroup()
# Set the name of the Click group in case someone wants to add
# the app's commands to another CLI tool.
self.cli.name = self.name
def get_send_file_max_age(self, filename: str | None) -> int | None:

@@ -21,0 +59,0 @@ """Used by :func:`send_file` to determine the ``max_age`` cache

@@ -232,4 +232,3 @@ from __future__ import annotations

module_name: str, app_name: str | None, raise_if_not_found: t.Literal[True] = True
) -> Flask:
...
) -> Flask: ...

@@ -240,4 +239,3 @@

module_name: str, app_name: str | None, raise_if_not_found: t.Literal[False] = ...
) -> Flask | None:
...
) -> Flask | None: ...

@@ -244,0 +242,0 @@

@@ -30,8 +30,6 @@ from __future__ import annotations

@t.overload
def __get__(self, obj: None, owner: None) -> te.Self:
...
def __get__(self, obj: None, owner: None) -> te.Self: ...
@t.overload
def __get__(self, obj: App, owner: type[App]) -> T:
...
def __get__(self, obj: App, owner: type[App]) -> T: ...

@@ -38,0 +36,0 @@ def __get__(self, obj: App | None, owner: type[App] | None = None) -> T | te.Self:

@@ -43,2 +43,3 @@ """

"""
from __future__ import annotations

@@ -45,0 +46,0 @@

@@ -413,6 +413,2 @@ from __future__ import annotations

# Set the name of the Click group in case someone wants to add
# the app's commands to another CLI tool.
self.cli.name = self.name
def _check_setup_finished(self, f_name: str) -> None:

@@ -419,0 +415,0 @@ if self._got_first_request:

@@ -11,3 +11,2 @@ from __future__ import annotations

import click
from jinja2 import BaseLoader

@@ -20,6 +19,8 @@ from jinja2 import FileSystemLoader

from .. import typing as ft
from ..cli import AppGroup
from ..helpers import get_root_path
from ..templating import _default_template_ctx_processor
if t.TYPE_CHECKING: # pragma: no cover
from click import Group
# a singleton sentinel value for parameter defaults

@@ -71,2 +72,3 @@ _sentinel = object()

cli: Group
name: str

@@ -103,8 +105,2 @@ _static_folder: str | None = None

#: The Click command group for registering CLI commands for this
#: object. The commands are available from the ``flask`` command
#: once the application has been discovered and blueprints have
#: been registered.
self.cli: click.Group = AppGroup()
#: A dictionary mapping endpoint names to view functions.

@@ -111,0 +107,0 @@ #:

@@ -280,2 +280,10 @@ from __future__ import annotations

def _lazy_sha1(string: bytes = b"") -> t.Any:
"""Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include
SHA-1, in which case the import and use as a default would fail before the
developer can configure something else.
"""
return hashlib.sha1(string)
class SecureCookieSessionInterface(SessionInterface):

@@ -290,3 +298,3 @@ """The default session interface that stores sessions in signed cookies

#: the hash function to use for the signature. The default is sha1
digest_method = staticmethod(hashlib.sha1)
digest_method = staticmethod(_lazy_sha1)
#: the name of the itsdangerous supported key derivation. The default

@@ -293,0 +301,0 @@ #: is hmac.

@@ -179,3 +179,3 @@ import datetime

test_uuid = uuid.UUID(bytes=b"\xDE\xAD\xBE\xEF" * 4)
test_uuid = uuid.UUID(bytes=b"\xde\xad\xbe\xef" * 4)
url = "/uuid_test"

@@ -182,0 +182,0 @@ app.add_url_rule(url, url, lambda: flask.jsonify(x=test_uuid))

@@ -20,18 +20,14 @@ from __future__ import annotations

@app.before_request
def before_sync() -> None:
...
def before_sync() -> None: ...
@app.before_request
async def before_async() -> None:
...
async def before_async() -> None: ...
@app.teardown_appcontext
def teardown_sync(exc: BaseException | None) -> None:
...
def teardown_sync(exc: BaseException | None) -> None: ...
@app.teardown_appcontext
async def teardown_async(exc: BaseException | None) -> None:
...
async def teardown_async(exc: BaseException | None) -> None: ...
+17
-3

@@ -5,3 +5,3 @@ [tox]

pypy310
py311-min
py312-min
py38-dev

@@ -23,3 +23,3 @@ style

dev: -r requirements-skip/tests-dev.txt
commands = pytest -v --tb=short --basetemp={envtmpdir} {posargs:tests}
commands = pytest -v --tb=short --basetemp={envtmpdir} {posargs}

@@ -37,2 +37,16 @@ [testenv:style]

deps = -r requirements/docs.txt
commands = sphinx-build -W -b html -d {envtmpdir}/doctrees docs {envtmpdir}/html
commands = sphinx-build -W -b dirhtml docs docs/_build/dirhtml
[testenv:update-requirements]
deps =
pip-tools
pre-commit
skip_install = true
change_dir = requirements
commands =
pre-commit autoupdate -j4
pip-compile -U build.in
pip-compile -U docs.in
pip-compile -U tests.in
pip-compile -U typing.in
pip-compile -U dev.in
Security Considerations
=======================
Web applications usually face all kinds of security problems and it's very
hard to get everything right. Flask tries to solve a few of these things
for you, but there are a couple more you have to take care of yourself.
.. _security-xss:
Cross-Site Scripting (XSS)
--------------------------
Cross site scripting is the concept of injecting arbitrary HTML (and with
it JavaScript) into the context of a website. To remedy this, developers
have to properly escape text so that it cannot include arbitrary HTML
tags. For more information on that have a look at the Wikipedia article
on `Cross-Site Scripting
<https://en.wikipedia.org/wiki/Cross-site_scripting>`_.
Flask configures Jinja2 to automatically escape all values unless
explicitly told otherwise. This should rule out all XSS problems caused
in templates, but there are still other places where you have to be
careful:
- generating HTML without the help of Jinja2
- calling :class:`~markupsafe.Markup` on data submitted by users
- sending out HTML from uploaded files, never do that, use the
``Content-Disposition: attachment`` header to prevent that problem.
- sending out textfiles from uploaded files. Some browsers are using
content-type guessing based on the first few bytes so users could
trick a browser to execute HTML.
Another thing that is very important are unquoted attributes. While
Jinja2 can protect you from XSS issues by escaping HTML, there is one
thing it cannot protect you from: XSS by attribute injection. To counter
this possible attack vector, be sure to always quote your attributes with
either double or single quotes when using Jinja expressions in them:
.. sourcecode:: html+jinja
<input value="{{ value }}">
Why is this necessary? Because if you would not be doing that, an
attacker could easily inject custom JavaScript handlers. For example an
attacker could inject this piece of HTML+JavaScript:
.. sourcecode:: html
onmouseover=alert(document.cookie)
When the user would then move with the mouse over the input, the cookie
would be presented to the user in an alert window. But instead of showing
the cookie to the user, a good attacker might also execute any other
JavaScript code. In combination with CSS injections the attacker might
even make the element fill out the entire page so that the user would
just have to have the mouse anywhere on the page to trigger the attack.
There is one class of XSS issues that Jinja's escaping does not protect
against. The ``a`` tag's ``href`` attribute can contain a `javascript:` URI,
which the browser will execute when clicked if not secured properly.
.. sourcecode:: html
<a href="{{ value }}">click here</a>
<a href="javascript:alert('unsafe');">click here</a>
To prevent this, you'll need to set the :ref:`security-csp` response header.
Cross-Site Request Forgery (CSRF)
---------------------------------
Another big problem is CSRF. This is a very complex topic and I won't
outline it here in detail just mention what it is and how to theoretically
prevent it.
If your authentication information is stored in cookies, you have implicit
state management. The state of "being logged in" is controlled by a
cookie, and that cookie is sent with each request to a page.
Unfortunately that includes requests triggered by 3rd party sites. If you
don't keep that in mind, some people might be able to trick your
application's users with social engineering to do stupid things without
them knowing.
Say you have a specific URL that, when you sent ``POST`` requests to will
delete a user's profile (say ``http://example.com/user/delete``). If an
attacker now creates a page that sends a post request to that page with
some JavaScript they just have to trick some users to load that page and
their profiles will end up being deleted.
Imagine you were to run Facebook with millions of concurrent users and
someone would send out links to images of little kittens. When users
would go to that page, their profiles would get deleted while they are
looking at images of fluffy cats.
How can you prevent that? Basically for each request that modifies
content on the server you would have to either use a one-time token and
store that in the cookie **and** also transmit it with the form data.
After receiving the data on the server again, you would then have to
compare the two tokens and ensure they are equal.
Why does Flask not do that for you? The ideal place for this to happen is
the form validation framework, which does not exist in Flask.
.. _security-json:
JSON Security
-------------
In Flask 0.10 and lower, :func:`~flask.jsonify` did not serialize top-level
arrays to JSON. This was because of a security vulnerability in ECMAScript 4.
ECMAScript 5 closed this vulnerability, so only extremely old browsers are
still vulnerable. All of these browsers have `other more serious
vulnerabilities
<https://github.com/pallets/flask/issues/248#issuecomment-59934857>`_, so
this behavior was changed and :func:`~flask.jsonify` now supports serializing
arrays.
Security Headers
----------------
Browsers recognize various response headers in order to control security. We
recommend reviewing each of the headers below for use in your application.
The `Flask-Talisman`_ extension can be used to manage HTTPS and the security
headers for you.
.. _Flask-Talisman: https://github.com/GoogleCloudPlatform/flask-talisman
HTTP Strict Transport Security (HSTS)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the browser to convert all HTTP requests to HTTPS, preventing
man-in-the-middle (MITM) attacks. ::
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
.. _security-csp:
Content Security Policy (CSP)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tell the browser where it can load various types of resource from. This header
should be used whenever possible, but requires some work to define the correct
policy for your site. A very strict policy would be::
response.headers['Content-Security-Policy'] = "default-src 'self'"
- https://csp.withgoogle.com/docs/index.html
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
X-Content-Type-Options
~~~~~~~~~~~~~~~~~~~~~~
Forces the browser to honor the response content type instead of trying to
detect it, which can be abused to generate a cross-site scripting (XSS)
attack. ::
response.headers['X-Content-Type-Options'] = 'nosniff'
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
X-Frame-Options
~~~~~~~~~~~~~~~
Prevents external sites from embedding your site in an ``iframe``. This
prevents a class of attacks where clicks in the outer frame can be translated
invisibly to clicks on your page's elements. This is also known as
"clickjacking". ::
response.headers['X-Frame-Options'] = 'SAMEORIGIN'
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
.. _security-cookie:
Set-Cookie options
~~~~~~~~~~~~~~~~~~
These options can be added to a ``Set-Cookie`` header to improve their
security. Flask has configuration options to set these on the session cookie.
They can be set on other cookies too.
- ``Secure`` limits cookies to HTTPS traffic only.
- ``HttpOnly`` protects the contents of cookies from being read with
JavaScript.
- ``SameSite`` restricts how cookies are sent with requests from
external sites. Can be set to ``'Lax'`` (recommended) or ``'Strict'``.
``Lax`` prevents sending cookies with CSRF-prone requests from
external sites, such as submitting a form. ``Strict`` prevents sending
cookies with all external requests, including following regular links.
::
app.config.update(
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE='Lax',
)
response.set_cookie('username', 'flask', secure=True, httponly=True, samesite='Lax')
Specifying ``Expires`` or ``Max-Age`` options, will remove the cookie after
the given time, or the current time plus the age, respectively. If neither
option is set, the cookie will be removed when the browser is closed. ::
# cookie expires after 10 minutes
response.set_cookie('snakes', '3', max_age=600)
For the session cookie, if :attr:`session.permanent <flask.session.permanent>`
is set, then :data:`PERMANENT_SESSION_LIFETIME` is used to set the expiration.
Flask's default cookie implementation validates that the cryptographic
signature is not older than this value. Lowering this value may help mitigate
replay attacks, where intercepted cookies can be sent at a later time. ::
app.config.update(
PERMANENT_SESSION_LIFETIME=600
)
@app.route('/login', methods=['POST'])
def login():
...
session.clear()
session['user_id'] = user.id
session.permanent = True
...
Use :class:`itsdangerous.TimedSerializer` to sign and validate other cookie
values (or any values that need secure signatures).
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
.. _samesite_support: https://caniuse.com/#feat=same-site-cookie-attribute
HTTP Public Key Pinning (HPKP)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This tells the browser to authenticate with the server using only the specific
certificate key to prevent MITM attacks.
.. warning::
Be careful when enabling this, as it is very difficult to undo if you set up
or upgrade your key incorrectly.
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning
Copy/Paste to Terminal
----------------------
Hidden characters such as the backspace character (``\b``, ``^H``) can
cause text to render differently in HTML than how it is interpreted if
`pasted into a terminal <https://security.stackexchange.com/q/39118>`__.
For example, ``import y\bose\bm\bi\bt\be\b`` renders as
``import yosemite`` in HTML, but the backspaces are applied when pasted
into a terminal, and it becomes ``import os``.
If you expect users to copy and paste untrusted code from your site,
such as from comments posted by users on a technical blog, consider
applying extra filtering, such as replacing all ``\b`` characters.
.. code-block:: python
body = body.replace("\b", "")
Most modern terminals will warn about and remove hidden characters when
pasting, so this isn't strictly necessary. It's also possible to craft
dangerous commands in other ways that aren't possible to filter.
Depending on your site's use case, it may be good to show a warning
about copying code in general.
Copyright 2010 Pallets
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Flask
=====
Flask is a lightweight `WSGI`_ web application framework. It is designed
to make getting started quick and easy, with the ability to scale up to
complex applications. It began as a simple wrapper around `Werkzeug`_
and `Jinja`_ and has become one of the most popular Python web
application frameworks.
Flask offers suggestions, but doesn't enforce any dependencies or
project layout. It is up to the developer to choose the tools and
libraries they want to use. There are many extensions provided by the
community that make adding new functionality easy.
.. _WSGI: https://wsgi.readthedocs.io/
.. _Werkzeug: https://werkzeug.palletsprojects.com/
.. _Jinja: https://jinja.palletsprojects.com/
Installing
----------
Install and update using `pip`_:
.. code-block:: text
$ pip install -U Flask
.. _pip: https://pip.pypa.io/en/stable/getting-started/
A Simple Example
----------------
.. code-block:: python
# save this as app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World!"
.. code-block:: text
$ flask run
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Contributing
------------
For guidance on setting up a development environment and how to make a
contribution to Flask, see the `contributing guidelines`_.
.. _contributing guidelines: https://github.com/pallets/flask/blob/main/CONTRIBUTING.rst
Donate
------
The Pallets organization develops and supports Flask and the libraries
it uses. In order to grow the community of contributors and users, and
allow the maintainers to devote more time to the projects, `please
donate today`_.
.. _please donate today: https://palletsprojects.com/donate
Links
-----
- Documentation: https://flask.palletsprojects.com/
- Changes: https://flask.palletsprojects.com/changes/
- PyPI Releases: https://pypi.org/project/Flask/
- Source Code: https://github.com/pallets/flask/
- Issue Tracker: https://github.com/pallets/flask/issues/
- Chat: https://discord.gg/pallets

Sorry, the diff of this file is too big to display