Source code for ResearchNotes.url_security

# -*- coding: utf-8 -*-
"""
Module to deal with url security or other security related stuff.

Module for improving security against cross-site request forgery (CSRF) attacks.
This is done by encoding the URLs with a security key ("SEC_SESSION_KEY" from
the app_configuration module) and salting a string unique to que current login
session.

"""

import typing
from flask import g, url_for, Blueprint, abort
from itsdangerous import URLSafeSerializer, BadSignature


bp = Blueprint("security", __name__, url_prefix="")


[docs]def token_encode(plain: typing.Any, salt: str, secret_key: str) -> typing.Union[str, bytes]: """ Encode obj with session salt. Encodes a plain text string using a secret key and a salt unique to the current login session (same as the decoder) Parameters ---------- plain: Any Plain text string salt : Union[Iterable[Union[str, bytes]] Salt unique to the current login session, default = g.salt secret_key : Union[Iterable[Union[str, bytes]] Secret key, default = current_app.config["SEC_SESSION_KEY"] Returns ------- str An encoded string """ return URLSafeSerializer(secret_key, salt).dumps(plain)
[docs]def token_decode(signed: str, salt: str, secret_key: str) -> typing.Any: """ Decode string with session salt. Decodes a signed string using a secret key and a salt unique to the current login session (same as the encoder) Parameters ---------- signed : str Encoded string salt : str Salt unique to the current login session, default = g.salt secret_key : str Secret key, default = current_app.config["SEC_SESSION_KEY"] Returns ------- Any A decoded string """ try: obj = URLSafeSerializer(secret_key, salt).loads(signed) except BadSignature: abort( 403, f" url_security : token_decode : User {g.user} tried to call " + " a save_url_for with wrong token (signature)", ) return obj
[docs]@bp.app_template_filter("safe_url_for") def safe_url_for(token: typing.Any, endpoint: str, secret_key: str, salt: str) -> str: """ Save url generator. Generates URLs in a similar manner to Flask's built-in url_for() function, but it encodes its keyword arguments to make them harder to guess for an attacker. Parameters ---------- token : Any Object to encode endpoint : str Name of the view to be called. It has to take a str (token) as argument. secret_key : Union[Iterable[Union[str, bytes]] Secret key for encoding. To be passed for token_encode. salt : Union[Iterable[Union[str, bytes]] Salt for encoding. To be passed for token_encode. Returns ------- str A safe URL for the given endpoint and token. Example ------- In the html you call save_url_for as filter {{obj | save_url_view(view)}} the view needs to have the signature: @rout(view/string:token) def view(token): obj = token_decode(token,...) """ return url_for(endpoint, token=token_encode(token, secret_key, salt))