pax_global_header00006660000000000000000000000064144627133250014521gustar00rootroot0000000000000052 comment=98a31bf2e6ef7eb9ee65b36f7dbec98f927d038a flask-talisman-1.1.0/000077500000000000000000000000001446271332500144265ustar00rootroot00000000000000flask-talisman-1.1.0/.github/000077500000000000000000000000001446271332500157665ustar00rootroot00000000000000flask-talisman-1.1.0/.github/FUNDING.yml000066400000000000000000000001221446271332500175760ustar00rootroot00000000000000# These are supported funding model platforms github: theacodes ko_fi: theacodes flask-talisman-1.1.0/.github/workflows/000077500000000000000000000000001446271332500200235ustar00rootroot00000000000000flask-talisman-1.1.0/.github/workflows/ci.yml000066400000000000000000000027221446271332500211440ustar00rootroot00000000000000# This workflow will install Python dependencies, run tests and lint with a single version of Python # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Flask Talisman on: push: branches: - "main" pull_request: branches: [ main ] jobs: lint: runs-on: ubuntu-latest steps: - name: Checkout Code Repository uses: actions/checkout@v3 - name: Set up Python 3.11 uses: actions/setup-python@v4 with: python-version: 3.11 - name: Install dependencies run: | pip install docutils pygments flake8 flake8-import-order pip install -e . - name: Check setup.py run: python setup.py check --metadata --restructuredtext --strict - name: Flake8 run: flake8 --import-order-style=google flask_talisman test: runs-on: ubuntu-latest strategy: matrix: python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | pip install flask mock pytest pytest-cov pip install -e . - name: Test run: | pytest --cov=flask_talisman --cov-report= coverage report --show-missing --fail-under=100 flask-talisman-1.1.0/.github/workflows/release.yml000066400000000000000000000010271446271332500221660ustar00rootroot00000000000000name: Upload Python Package on: release: types: [published] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 - name: Install dependencies run: | python -m pip install --upgrade pip pip install setuptools wheel twine - name: Build and publish env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | python setup.py sdist bdist_wheel twine upload dist/* flask-talisman-1.1.0/.gitignore000066400000000000000000000040151446271332500164160ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder .pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: # .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ .idea/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # Cython debug symbols cython_debug/ # VS Code .vscode flask-talisman-1.1.0/CONTRIBUTING.md000066400000000000000000000007221446271332500166600ustar00rootroot00000000000000# Contributing Flask-Talisman loves help from anyone in the community. You can do so in the following steps: - Fork the repository. - Write your contribution. Don't forget to add tests! - Run tests and linting locally by running `nox` in the root of the project. - If everything passes, submit a [pull request](https://github.com/wntrblm/flask-talisman/compare/). At this point you're waiting on us. We like to at least comment on pull requests within a few days.flask-talisman-1.1.0/LICENSE000066400000000000000000000261351446271332500154420ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. flask-talisman-1.1.0/README.rst000066400000000000000000000424521446271332500161240ustar00rootroot00000000000000Talisman: HTTP security headers for Flask ========================================= |PyPI Version| Talisman is a small Flask extension that handles setting HTTP headers that can help protect against a few common web application security issues. The default configuration: - Forces all connects to ``https``, unless running with debug enabled. - Enables `HTTP Strict Transport Security `_. - Sets Flask's session cookie to ``secure``, so it will never be set if your application is somehow accessed via a non-secure connection. - Sets Flask's session cookie to ``httponly``, preventing JavaScript from being able to access its content. CSRF via Ajax uses a separate cookie and should be unaffected. - Sets Flask's session cookie to ``Lax``, preventing the cookie to be leaked in CSRF-prone request methods. - Sets `X-Frame-Options `_ to ``SAMEORIGIN`` to avoid `clickjacking `_. - Sets `X-Content-Type-Options `_ to prevent content type sniffing. - Sets a strict `Content Security Policy `__ of ``default-src: 'self', 'object-src': 'none'``. This is intended to almost completely prevent Cross Site Scripting (XSS) attacks. This is probably the only setting that you should reasonably change. See the `Content Security Policy`_ section. - Sets a strict `Referrer-Policy `_ of ``strict-origin-when-cross-origin`` that governs which referrer information should be included with requests made. - Disables ``browsing-topics`` by default in the `Permissions-Policy `_ like `Drupal `_ to enhance privacy protection. In addition to Talisman, you **should always use a cross-site request forgery (CSRF) library**. It's highly recommended to use `Flask-SeaSurf `_, which is based on Django's excellent library. Installation & Basic Usage -------------------------- Install via `pip `_: :: pip install flask-talisman After installing, wrap your Flask app with a ``Talisman``: .. code:: python from flask import Flask from flask_talisman import Talisman app = Flask(__name__) Talisman(app) There is also a full `Example App `_. Options ------- - ``force_https``, default ``True``, forces all non-debug connects to ``https`` (`about HTTPS `_). - ``force_https_permanent``, default ``False``, uses ``301`` instead of ``302`` for ``https`` redirects. - ``frame_options``, default ``SAMEORIGIN``, can be ``SAMEORIGIN``, ``DENY``, or ``ALLOWFROM`` (`about Frame Options `_). - ``frame_options_allow_from``, default ``None``, a string indicating the domains that are allowed to embed the site via iframe. - ``strict_transport_security``, default ``True``, whether to send HSTS headers (`about HSTS `_). - ``strict_transport_security_preload``, default ``False``, enables HSTS preloading. If you register your application with `Google's HSTS preload list `_, Firefox and Chrome will never load your site over a non-secure connection. - ``strict_transport_security_max_age``, default ``ONE_YEAR_IN_SECS``, length of time the browser will respect the HSTS header. - ``strict_transport_security_include_subdomains``, default ``True``, whether subdomains should also use HSTS. - ``content_security_policy``, default ``default-src: 'self'`, 'object-src': 'none'``, see the `Content Security Policy`_ section (`about Content Security Policy `_). - ``content_security_policy_nonce_in``, default ``[]``. Adds a per-request nonce value to the flask request object and also to the specified CSP header section. I.e. ``['script-src', 'style-src']`` - ``content_security_policy_report_only``, default ``False``, whether to set the CSP header as "report-only" (as `Content-Security-Policy-Report-Only`) to ease deployment by disabling the policy enforcement by the browser, requires passing a value with the ``content_security_policy_report_uri`` parameter - ``content_security_policy_report_uri``, default ``None``, a string indicating the report URI used for `CSP violation reports `_ - ``referrer_policy``, default ``strict-origin-when-cross-origin``, a string that sets the Referrer Policy header to send a full URL when performing a same-origin request, only send the origin of the document to an equally secure destination (HTTPS->HTTPS), and send no header to a less secure destination (HTTPS->HTTP) (`about Referrer Policy `_). - ``feature_policy``, default ``{}``, see the `Feature Policy`_ section (`about Feature Policy `_). - ``permissions_policy``, default ``{'browsing-topics': '()'}``, see the `Permissions Policy`_ section (`about Permissions Policy `_). - ``document_policy``, default ``{}``, see the `Document Policy`_ section (`about Document Policy `_). - ``session_cookie_secure``, default ``True``, set the session cookie to ``secure``, preventing it from being sent over plain ``http`` (`about cookies (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie)_`). - ``session_cookie_http_only``, default ``True``, set the session cookie to ``httponly``, preventing it from being read by JavaScript. - ``session_cookie_samesite``, default ``Lax``, set this to ``Strict`` to prevent the cookie from being sent by the browser to the target site in all cross-site browsing context, even when following a regular link. - ``force_file_save``, default ``False``, whether to set the `X-Download-Options `_ header to ``noopen`` to prevent IE >= 8 to from opening file downloads directly and only save them instead. - ``x_content_type_options``, default ``True``, Protects against MIME sniffing vulnerabilities (`about Content Type Options `_). - ``x_xss_protection``, default ``False``, Protects against cross-site scripting (XSS) attacks (`about XSS Protection `_). This option is disabled by default because no modern browser (`supports this header `_) anymore. For a full list of (security) headers, check out: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers. Per-view options ~~~~~~~~~~~~~~~~ Sometimes you want to change the policy for a specific view. The ``force_https``, ``frame_options``, ``frame_options_allow_from``, `content_security_policy``, ``feature_policy``, ``permissions_policy`` and ``document_policy`` options can be changed on a per-view basis. .. code:: python from flask import Flask from flask_talisman import Talisman, ALLOW_FROM app = Flask(__name__) talisman = Talisman(app) @app.route('/normal') def normal(): return 'Normal' @app.route('/embeddable') @talisman(frame_options=ALLOW_FROM, frame_options_allow_from='*') def embeddable(): return 'Embeddable' Content Security Policy ----------------------- The default content security policy is extremely strict and will prevent loading any resources that are not in the same domain as the application. Most web applications will need to change this policy. If you're not ready to deploy Content Security Policy, you can set `content_security_policy` to `False` to disable sending this header entirely. A slightly more permissive policy is available at ``flask_talisman.GOOGLE_CSP_POLICY``, which allows loading Google-hosted JS libraries, fonts, and embeding media from YouTube and Maps. You can and should create your own policy to suit your site's needs. Here's a few examples adapted from `MDN `_: Example 1 ~~~~~~~~~ This is the default policy. A web site administrator wants all content to come from the site's own origin (this excludes subdomains) and disallow legacy HTML elements. .. code:: python csp = { 'default-src': '\'self\'', 'object-src': '\'none\'', } talisman = Talisman(app, content_security_policy=csp) Example 2 ~~~~~~~~~ A web site administrator wants to allow content from a trusted domain and all its subdomains (it doesn't have to be the same domain that the CSP is set on.) .. code:: python csp = { 'default-src': [ '\'self\'', '*.trusted.com' ] } Example 3 ~~~~~~~~~ A web site administrator wants to allow users of a web application to include images from any origin in their own content, but to restrict audio or video media to trusted providers, and all scripts only to a specific server that hosts trusted code. .. code:: python csp = { 'default-src': '\'self\'', 'img-src': '*', 'media-src': [ 'media1.com', 'media2.com', ], 'script-src': 'userscripts.example.com' } In this example content is only permitted from the document's origin with the following exceptions: - Images may loaded from anywhere (note the ``*`` wildcard). - Media is only allowed from media1.com and media2.com (and not from subdomains of those sites). - Executable script is only allowed from userscripts.example.com. Example 4 ~~~~~~~~~ A web site administrator for an online banking site wants to ensure that all its content is loaded using SSL, in order to prevent attackers from eavesdropping on requests. .. code:: python csp = { 'default-src': 'https://onlinebanking.jumbobank.com' } The server only permits access to documents being loaded specifically over HTTPS through the single origin onlinebanking.jumbobank.com. Example 5 ~~~~~~~~~ A web site administrator of a web mail site wants to allow HTML in email, as well as images loaded from anywhere, but not JavaScript or other potentially dangerous content. .. code:: python csp = { 'default-src': [ '\'self\'', '*.mailsite.com', ], 'img-src': '*' } Note that this example doesn't specify a ``script-src``; with the example CSP, this site uses the setting specified by the ``default-src`` directive, which means that scripts can be loaded only from the originating server. Example 6 ~~~~~~~~~ A web site administrator wants to allow embedded scripts (which might be generated dynamicially). .. code:: python csp = { 'default-src': '\'self\'', 'script-src': '\'self\'', } talisman = Talisman( app, content_security_policy=csp, content_security_policy_nonce_in=['script-src'] ) The nonce needs to be added to the script tag in the template: .. code:: html Note that the CSP directive (`script-src` in the example) to which the `nonce-...` source should be added needs to be defined explicitly. Example 7 ~~~~~~~~~ A web site adminstrator wants to override the CSP directives via an environment variable which doesn't support specifying the policy as a Python dictionary, e.g.: .. code:: bash export CSP_DIRECTIVES="default-src 'self'; image-src *" python app.py Then in the app code you can read the CSP directives from the environment: .. code:: python import os from flask_talisman import Talisman, DEFAULT_CSP_POLICY talisman = Talisman( app, content_security_policy=os.environ.get("CSP_DIRECTIVES", DEFAULT_CSP_POLICY), ) As you can see above the policy can be defined simply just like the official specification requires the HTTP header to be set: As a semicolon separated list of individual CSP directives. Feature Policy -------------- **Note:** Feature Policy has largely been `renamed Permissions Policy `_ in the latest draft and some features are likely to move to Document Policy. At this writing, most browsers support the ``Feature-Policy`` HTTP Header name. See the `Permissions Policy`_ and `Document Policy`_ sections below should you wish to set these. Also note that the Feature Policy specification did not progress beyond the `draft https://wicg.github.io/feature-policy/` stage before being renamed, but is `supported in some form in most browsers `_. The default feature policy is empty, as this is the default expected behaviour. Geolocation Example ~~~~~~~~~~~~~~~~~~~ Disable access to Geolocation interface. .. code:: python feature_policy = { 'geolocation': '\'none\'' } talisman = Talisman(app, feature_policy=feature_policy) Permissions Policy ------------------ Feature Policy has been split into Permissions Policy and Document Policy but at this writing `browser support of Permissions Policy is very limited `_, and it is recommended to still set the ``Feature-Policy`` HTTP Header. Permission Policy support is included in Talisman for when this becomes more widely supported. Note that the `Permission Policy is still an Working Draft `_. When the same feature or permission is set in both Feature Policy and Permission Policy, the Permission Policy setting will take precedence in browsers that support both. It should be noted that the syntax differs between Feature Policy and Permission Policy as can be seen from the ``geolocation`` examples provided. The default Permissions Policy is ``browsing-topics=()``, which opts sites out of `Federated Learning of Cohorts `_ an interest-based advertising initiative called Topics API. Permission Policy can be set either using a dictionary, or using a string. Geolocation and Microphone Example ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Disable access to Geolocation interface and Microphone using dictionary syntax .. code:: python permissions_policy = { 'geolocation': '()', 'microphone': '()' } talisman = Talisman(app, permissions_policy=permissions_policy) Disable access to Geolocation interface and Microphone using string syntax .. code:: python permissions_policy = 'geolocation=(), microphone=()' talisman = Talisman(app, permissions_policy=permissions_policy) Document Policy --------------- Feature Policy has been split into Permissions Policy and Document Policy but at this writing `browser support of Document Policy is very limited `_, and it is recommended to still set the ``Feature-Policy`` HTTP Header. Document Policy support is included in Talisman for when this becomes more widely supported. Note that the `Document Policy is still an Unofficial Draft `_. The default Document Policy is empty, as this is the default expected behaviour. Document Policy can be set either using a dictionary, or using a string. Oversized-Images Example ~~~~~~~~~~~~~~~~~~~~~~~~ Forbid oversized-images using dictionary syntax: .. code:: python document_policy = { 'oversized-images': '?0' } talisman = Talisman(app, document_policy=document_policy) Forbid oversized-images using string syntax: .. code:: python document_policy = 'oversized-images=?0' talisman = Talisman(app, document_policy=document_policy) Disclaimer ---------- This code originated at Google, but is not an official Google product, experimental or otherwise. It was forked on June 6th, 2021 from the unmaintained GoogleCloudPlatform/flask-talisman. There is no silver bullet for web application security. Talisman can help, but security is more than just setting a few headers. Any public-facing web application should have a comprehensive approach to security. Contributing changes -------------------- - See `CONTRIBUTING.md`_ Licensing --------- - Apache 2.0 - See `LICENSE`_ .. _LICENSE: https://github.com/wntrblm/flask-talisman/blob/master/LICENSE .. _CONTRIBUTING.md: https://github.com/wntrblm/flask-talisman/blob/master/CONTRIBUTING.md .. |PyPI Version| image:: https://img.shields.io/pypi/v/flask-talisman.svg :target: https://pypi.python.org/pypi/flask-talisman flask-talisman-1.1.0/example_app/000077500000000000000000000000001446271332500167215ustar00rootroot00000000000000flask-talisman-1.1.0/example_app/Dockerfile000066400000000000000000000005241446271332500207140ustar00rootroot00000000000000FROM gcr.io/google_appengine/python RUN virtualenv /env -p python3.4 # Set virtualenv environment variables. This is equivalent to running # source /env/bin/activate ENV VIRTUAL_ENV /env ENV PATH /env/bin:$PATH ADD requirements.txt /app/ RUN pip install -r requirements.txt ADD . /app/ CMD gunicorn -c gunicorn.conf.py -b :$PORT main:app flask-talisman-1.1.0/example_app/app.yaml000066400000000000000000000000551446271332500203650ustar00rootroot00000000000000runtime: custom env: flex entrypoint: custom flask-talisman-1.1.0/example_app/gunicorn.conf.py000066400000000000000000000012721446271332500220450ustar00rootroot00000000000000# Copyright 2015 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # GAE serves requests from a reverse proxy. forwarded_allow_ips = '*' secure_scheme_headers = {'X-APPENGINE-HTTPS': 'on'} flask-talisman-1.1.0/example_app/main.py000066400000000000000000000033301446271332500202160ustar00rootroot00000000000000# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from flask import Flask, render_template, request from flask_seasurf import SeaSurf from flask_talisman import Talisman app = Flask(__name__) app.secret_key = '123abc' csrf = SeaSurf(app) SELF = "'self'" talisman = Talisman( app, content_security_policy={ 'default-src': SELF, 'img-src': '*', 'script-src': [ SELF, 'some.cdn.com', ], 'style-src': [ SELF, 'another.cdn.com', ], }, content_security_policy_nonce_in=['script-src'], feature_policy={ 'geolocation': '\'none\'', }, permissions_policy={ 'geolocation': '()', } ) @app.route('/', methods=['GET', 'POST']) def index(): message = request.form.get('message', None) return render_template('index.html', message=message) # Example of a route-specific talisman configuration @app.route('/embeddable') @talisman( frame_options='ALLOW-FROM', frame_options_allow_from='https://example.com/', ) def embeddable(): return "I can be embedded." if __name__ == '__main__': app.run(host='127.0.0.1', port=8080, debug=True) flask-talisman-1.1.0/example_app/requirements.txt000066400000000000000000000000671446271332500222100ustar00rootroot00000000000000Flask gunicorn flask-seasurf six>=1.9.0 flask-talisman flask-talisman-1.1.0/example_app/templates/000077500000000000000000000000001446271332500207175ustar00rootroot00000000000000flask-talisman-1.1.0/example_app/templates/index.html000066400000000000000000000025061446271332500227170ustar00rootroot00000000000000{# # Copyright 2015 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #} Talisman sample app

Talisman + Seasurf Sample

{% if message: %}

Your message:

{{message}}
{% endif %}
flask-talisman-1.1.0/flask_talisman/000077500000000000000000000000001446271332500174165ustar00rootroot00000000000000flask-talisman-1.1.0/flask_talisman/__init__.py000066400000000000000000000020031446271332500215220ustar00rootroot00000000000000# Copyright 2015 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from .talisman import ( ALLOW_FROM, DEFAULT_CSP_POLICY, DEFAULT_DOCUMENT_POLICY, DEFAULT_FEATURE_POLICY, DEFAULT_PERMISSIONS_POLICY, DENY, GOOGLE_CSP_POLICY, NONCE_LENGTH, SAMEORIGIN, Talisman) __all__ = ( 'ALLOW_FROM', 'DEFAULT_CSP_POLICY', 'DEFAULT_DOCUMENT_POLICY', 'DEFAULT_FEATURE_POLICY', 'DEFAULT_PERMISSIONS_POLICY', 'DENY', 'GOOGLE_CSP_POLICY', 'NONCE_LENGTH', 'SAMEORIGIN', 'Talisman', ) flask-talisman-1.1.0/flask_talisman/talisman.py000066400000000000000000000412111446271332500215770ustar00rootroot00000000000000# Copyright 2015 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from collections import OrderedDict import flask DENY = 'DENY' SAMEORIGIN = 'SAMEORIGIN' ALLOW_FROM = 'ALLOW-FROM' ONE_YEAR_IN_SECS = 31556926 DEFAULT_REFERRER_POLICY = 'strict-origin-when-cross-origin' DEFAULT_CSP_POLICY = { 'default-src': '\'self\'', 'object-src': '\'none\'', } DEFAULT_SESSION_COOKIE_SAMESITE = "Lax" GOOGLE_CSP_POLICY = { # Fonts from fonts.google.com 'font-src': '\'self\' themes.googleusercontent.com *.gstatic.com', #