diff --git a/owasp-top10-2021-apps/a9/games-irados/app/requirements.txt b/owasp-top10-2021-apps/a9/games-irados/app/requirements.txt index 712b5fad3..1984b86e8 100644 --- a/owasp-top10-2021-apps/a9/games-irados/app/requirements.txt +++ b/owasp-top10-2021-apps/a9/games-irados/app/requirements.txt @@ -10,3 +10,4 @@ mysqlclient==1.3.13 six==1.11.0 visitor==0.1.3 Werkzeug==0.14.1 +pytz==2024.1 diff --git a/owasp-top10-2021-apps/a9/games-irados/app/routes.py b/owasp-top10-2021-apps/a9/games-irados/app/routes.py index eddd6a999..3dad003ae 100644 --- a/owasp-top10-2021-apps/a9/games-irados/app/routes.py +++ b/owasp-top10-2021-apps/a9/games-irados/app/routes.py @@ -1,15 +1,11 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from functools import wraps import uuid -import datetime +from functools import wraps from flask import ( Flask, render_template, request, redirect, flash, - make_response, session ) from util.init_db import init_db @@ -19,32 +15,62 @@ from model.db import DataBase import logging import os +from datetime import datetime from flask_cors import CORS, cross_origin -from model.db import DataBase app = Flask(__name__) bootstrap = Bootstrap(app) app.config.from_pyfile('config.py') +# Remove default logging configuration +logging.getLogger().setLevel(logging.NOTSET) +app.logger.handlers = [] + +# Configure logger for __main__ +logger = logging.getLogger(__name__) +formatter = logging.Formatter('%(levelname)s: %(message)s') +stream_handler = logging.StreamHandler() +stream_handler.setFormatter(formatter) +logger.addHandler(stream_handler) +logger.setLevel(logging.INFO) + +# Configure werkzeug logger +werkzeug_logger = logging.getLogger('werkzeug') +werkzeug_logger.setLevel(logging.INFO) +werkzeug_handler = logging.StreamHandler() +werkzeug_formatter = logging.Formatter('%(message)s') +werkzeug_handler.setFormatter(werkzeug_formatter) +werkzeug_logger.addHandler(werkzeug_handler) + +# Remove default werkzeug logger handler +if werkzeug_logger.hasHandlers(): + werkzeug_logger.handlers.clear() + +# Custom Request Logger +class RequestLogger(logging.LoggerAdapter): + def process(self, msg, kwargs): + request_info = request + ip = request_info.remote_addr + timestamp = datetime.now().strftime('%d/%b/%Y %H:%M:%S') + method = request_info.method + path = request_info.path + status_code = kwargs.pop('status_code', '-') + msg += f' - {ip} - - [{timestamp}] "{method} {path} HTTP/1.1" {status_code} -' + return msg, kwargs + +request_logger = RequestLogger(logger, {}) def generate_csrf_token(): - ''' - Generate csrf token and store it in session - ''' if '_csrf_token' not in session: session['_csrf_token'] = str(uuid.uuid4()) return session.get('_csrf_token') - app.jinja_env.globals['csrf_token'] = generate_csrf_token @app.before_request def csrf_protect(): - ''' - CSRF PROTECION - ''' if request.method == "POST": token_csrf = session.get('_csrf_token') form_token = request.form.get('_csrf_token') @@ -55,7 +81,7 @@ def login_required(f): @wraps(f) def decorated_function(*args, **kwargs): if 'username' not in session: - flash('oops, session expired', "danger") + flash('Oops, session expired', "danger") return redirect('/login') return f(*args, **kwargs) return decorated_function @@ -76,10 +102,12 @@ def login(): username = request.form.get('username').encode('utf-8') psw = Password(request.form.get('password').encode('utf-8')) user_password, success = database.get_user_password(username) - if not success or user_password == None or not psw.validate_password(str(user_password[0])): - flash("Usuario ou senha incorretos", "danger") + if not success or user_password is None or not psw.validate_password(str(user_password[0])): + request_logger.info("login inválido!", extra={'status_code': 200}) + flash("Usuário ou senha incorretos", "danger") return render_template('login.html') session['username'] = username + request_logger.info("login efetuado com sucesso!", extra={'status_code': 302}) return redirect('/home') else: return render_template('login.html') @@ -96,13 +124,13 @@ def newuser(): hashed_psw = psw.get_hashed_password() message, success = database.insert_user(username, hashed_psw) if success == 1: - flash("Novo usuario adicionado!", "primary") + flash("Novo usuário adicionado!", "primary") return redirect('/login') else: flash(message, "danger") return redirect('/register') - flash("Passwords must be the same!", "danger") + flash("As senhas devem ser iguais!", "danger") return redirect('/register') else: return render_template('register.html') @@ -117,15 +145,24 @@ def home(): def cupom(): if request.method == 'POST': coupon = request.form.get('coupon') - rows, success = database.get_game_coupon(coupon, session.get('username')) - if not success or rows == None or rows == 0: - flash("Cupom invalido", "danger") + username = session.get('username') + if coupon: + coupon_display = '****' # Oculta o valor do cupom + else: + coupon_display = coupon + + request_logger.info(f'User: "id do usuário" attempted to redeem coupon: {coupon_display} - Result: Invalid', extra={'status_code': 200}) + + rows, success = database.get_game_coupon(coupon, username) + if not success or rows is None or rows == 0: + flash("Cupom inválido", "danger") return render_template('coupon.html') - game, success = database.get_game(coupon, session.get('username')) - if not success or game == None: - flash("Cupom invalido", "danger") + game, success = database.get_game(coupon, username) + if not success or game is None: + flash("Cupom inválido", "danger") return render_template('coupon.html') - flash("Voce ganhou {}".format(game[0]), "primary") + request_logger.info(f'User: "id do usuário" redeemed coupon: {coupon_display} - Result: Valid', extra={'status_code': 200}) + flash("Você ganhou {}".format(game[0]), "primary") return render_template('coupon.html') else: return render_template('coupon.html') @@ -137,4 +174,4 @@ def cupom(): dbName = os.environ.get('MYSQL_DB') database = DataBase(dbEndpoint, dbUser, dbPassword, dbName) init_db(database) - app.run(host='0.0.0.0',port=10010, debug=True) + app.run(host='0.0.0.0', port=10010, debug=True) diff --git a/owasp-top10-2021-apps/a9/games-irados/poc.txt b/owasp-top10-2021-apps/a9/games-irados/poc.txt new file mode 100644 index 000000000..92a0820c4 --- /dev/null +++ b/owasp-top10-2021-apps/a9/games-irados/poc.txt @@ -0,0 +1,10 @@ +admin +password +123 +qweasd +1qaz +123456789 +flamengo +zxc +asd123qwe +YOURVALIDPASSWORD \ No newline at end of file