From f3196b7ec54cff5767c664d3429155d181180289 Mon Sep 17 00:00:00 2001 From: Nicolas Valcarcel Date: Thu, 12 Sep 2019 21:55:23 -0500 Subject: [PATCH 1/4] Change password --- README.md | 22 +++++++----- marketplace/__init__.py | 3 +- marketplace/helpers.py | 21 +++++++++++ .../templates/users/change_password.html | 23 ++++++++++++ marketplace/templates/users/welcome.html | 4 +-- marketplace/users.py | 35 ++++++++++++------- 6 files changed, 84 insertions(+), 24 deletions(-) create mode 100644 marketplace/helpers.py create mode 100644 marketplace/templates/users/change_password.html diff --git a/README.md b/README.md index 8ea21ff..39eb14f 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,21 @@ # Secure Coding with Python. ## Chapter 5: Broken De-Authentication -### Fix -In order to avoid sessions to be used even after the user has logged out, we should use a random unique value in the -session that we could revoke on logout, invalidating the session. +### Requirement +Continuing with the user account, we should allow the user to change their password. -Since we are adding a new column to our user model we need to update our Database with: -```bash -> $ flask db migrate -> $ flask db upgrade -``` +### Development +We add a simple form that allows a user to enter their current password and a new password. -**Proceed to [next section](https://github.com/nxvl/secure-coding-with-python/tree/5.2-broken-deauthentication/code)** +*Note*: For simplicity we aren't going to add a repeat your password field, but on a real world scenario you probably should. + +### Vulnerability +Most of the times a user changes their password is because of suspicion of account compromise. If an attacker has already +gotten their hands on the user credentials, changing the password is expected to prevent further access from +the attacker. By changing the password, but not invalidating the `session_key` and attacker can keep their +access to the compromised account, contrary to the user expectations. + +**Proceed to [next section](https://github.com/nxvl/secure-coding-with-python/tree/5.2-broken-deauthentication/test)** ## Index ### 1. Vulnerable Components diff --git a/marketplace/__init__.py b/marketplace/__init__.py index d4a8872..7c1c428 100644 --- a/marketplace/__init__.py +++ b/marketplace/__init__.py @@ -8,6 +8,7 @@ db = SQLAlchemy() migrate = Migrate() + def create_app(test_config=None): app = Flask(__name__, instance_relative_config=True) app.config.from_mapping( @@ -29,4 +30,4 @@ def create_app(test_config=None): app.register_blueprint(listings.bp) app.register_blueprint(users.bp) - return app \ No newline at end of file + return app diff --git a/marketplace/helpers.py b/marketplace/helpers.py new file mode 100644 index 0000000..4dd8a5a --- /dev/null +++ b/marketplace/helpers.py @@ -0,0 +1,21 @@ +from flask import session, redirect, url_for + +from .models import User +from . import db + + +def auth(func): + def decorated_function(*args, **kwargs): + key = session.get('key') + if not key: + return redirect(url_for('users.login')) + + user = db.session.query(User).filter_by(session_key=key).scalar() + if not user: + return redirect(url_for('users.login')) + + return func(user, *args, **kwargs) + + decorated_function.__name__ = func.__name__ + return decorated_function + diff --git a/marketplace/templates/users/change_password.html b/marketplace/templates/users/change_password.html new file mode 100644 index 0000000..ccebe58 --- /dev/null +++ b/marketplace/templates/users/change_password.html @@ -0,0 +1,23 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}Change your password{% endblock %}

+{% endblock %} + +{% block content %} +Hello {{user.full_name}}, please enter your current password and the new one you want to use: + +{% if msg %} +

{{msg}}

+{% endif %} + +
+ + +
+ + +
+ +
+{% endblock %} diff --git a/marketplace/templates/users/welcome.html b/marketplace/templates/users/welcome.html index 061d57b..6ba7c6b 100644 --- a/marketplace/templates/users/welcome.html +++ b/marketplace/templates/users/welcome.html @@ -5,6 +5,6 @@

{% block title %}Welcome{% endblock %}

{% endblock %} {% block content %} -Logout
-Welcome to the marketplace! +Logout  Change Password
+Welcome {{user.full_name}} to the marketplace! {% endblock %} diff --git a/marketplace/users.py b/marketplace/users.py index 709607c..c362efd 100644 --- a/marketplace/users.py +++ b/marketplace/users.py @@ -2,6 +2,7 @@ from flask import Blueprint, request, render_template, session, url_for, redirect from . import db +from .helpers import auth from .models import User bp = Blueprint('users', __name__, url_prefix='/user') @@ -39,19 +40,29 @@ def login(): @bp.route('/logout', methods=('GET',)) -def logout(): - if session.get('key'): - key = session.pop('key') - u = db.session.query(User).filter_by(session_key=key).scalar() - u.new_session_key() - db.session.commit() +@auth +def logout(user): + session.pop('key') + user.new_session_key() + db.session.commit() return redirect(url_for('users.login')) @bp.route('/welcome', methods=('GET',)) -def welcome(): - key = session.get('key') - if key and db.session.query(User).filter_by(session_key=key).scalar(): - return render_template('users/welcome.html') - else: - return redirect(url_for('users.login')) +@auth +def welcome(user): + return render_template('users/welcome.html', user=user) + + +@bp.route('/change_password', methods=('GET', 'POST')) +@auth +def change_password(user): + msg = None + if request.method == 'POST': + if bcrypt.checkpw(request.form['current_password'].encode(), user.password.encode()): + user.password = request.form['new_password'] + db.session.commit() + msg = "Password change successful" + else: + msg = "Incorrect current password" + return render_template('users/change_password.html', user=user, msg=msg) From 5ebb1c4996ef0239b98c1639f7e5caed96b79583 Mon Sep 17 00:00:00 2001 From: Nicolas Valcarcel Date: Thu, 12 Sep 2019 22:28:28 -0500 Subject: [PATCH 2/4] instructions to test using OWASP ZAP --- README.md | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 39eb14f..d43be32 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,32 @@ # Secure Coding with Python. ## Chapter 5: Broken De-Authentication -### Requirement -Continuing with the user account, we should allow the user to change their password. +### Test +Since the vulnerability is the same as the prior chapter, the test is also very similar, this time we are going to +use [OWASP Zed Attack Proxy](https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project), or ZAP for short. -### Development -We add a simple form that allows a user to enter their current password and a new password. +1. Please download and install ZAP. +2. Run ZAP. It will ask if you want to persist the ZAP Session. +3. Select `No, i do not want to persist this session at this mement in time` and uncheck `Remember my choice and do not ask me again`. +4. Click `Start`. +5. On the top right, find the icon `Open the browser you've chosen in the Quick Start tab pre-configured to proxy trough ZAP`. In my case it had the firefox icon. +6. Navigate to [http://localhost:5000/user/login](http://localhost:5000/user/login) +7. Login with the credentials of the user you created. +8. On `ZAP` go to the `History` tab in the bottom half of the window. +9. Find the `/user/welcome` request. +10. Go to the `Request` tab in the top half of the window. +11. On the header section you can see the cookie being sent like `Cookie: session=eyJrZXkiOiJHSDFWdThPbFdKRExWbU9ZTGY2SkJJMXJ5NUZNRlIwNVhoWTUwanFwZUxRIn0.XXsIUA.nNZ8EN3ty3HfsUjzTrEKZ9mzNPQ` +12. Copy the cookie value. +13. Go ahead and change the password in [http://localhost:5000/user/change_password](http://localhost:5000/user/change_password) +14. Once again click on`Open the browser you've chosen in the Quick Start tab pre-configured to proxy trough ZAP`. In my case it had the firefox icon. +15. In the new browser confirm you are not logged in by going to [http://localhost:5000/user/welcome](http://localhost:5000/user/welcome) +16. You should get redirected to the login page. +17. On `ZAP` click on `Set break on all requests and responses`. Should be a green circle icon. +18. On your unauthenticated browser, go to [http://localhost:5000/user/welcome](http://localhost:5000/user/welcome). +19. On `ZAP` insert the cookie value copied in step 11 in the headers section of the breakpoint. +20. On the top click on `Submit and continue to next break point`. Which will look like a play icon. -*Note*: For simplicity we aren't going to add a repeat your password field, but on a real world scenario you probably should. - -### Vulnerability -Most of the times a user changes their password is because of suspicion of account compromise. If an attacker has already -gotten their hands on the user credentials, changing the password is expected to prevent further access from -the attacker. By changing the password, but not invalidating the `session_key` and attacker can keep their -access to the compromised account, contrary to the user expectations. +As you can see even after the user changed their password, we were able to log in using the session value captured previously successfully performing a session hijacking attack. **Proceed to [next section](https://github.com/nxvl/secure-coding-with-python/tree/5.2-broken-deauthentication/test)** From 5ba96e5981d3164e3eb3fa809a6ce4fae03c7e98 Mon Sep 17 00:00:00 2001 From: Nicolas Valcarcel Date: Thu, 12 Sep 2019 22:28:51 -0500 Subject: [PATCH 3/4] update next section link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d43be32..08ecdf2 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ use [OWASP Zed Attack Proxy](https://www.owasp.org/index.php/OWASP_Zed_Attack_Pr As you can see even after the user changed their password, we were able to log in using the session value captured previously successfully performing a session hijacking attack. -**Proceed to [next section](https://github.com/nxvl/secure-coding-with-python/tree/5.2-broken-deauthentication/test)** +**Proceed to [next section](https://github.com/nxvl/secure-coding-with-python/tree/5.2-broken-deauthentication/fix)** ## Index ### 1. Vulnerable Components From b08c64b615cc1435db236b9d7af803126204af63 Mon Sep 17 00:00:00 2001 From: Nicolas Valcarcel Date: Fri, 13 Sep 2019 21:48:46 -0500 Subject: [PATCH 4/4] update README --- README.md | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index effe87f..f7102cb 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,21 @@ # Secure Coding with Python. ## Chapter 5: Broken De-Authentication -### Test -Since the vulnerability is the same as the prior chapter, the test is also very similar, this time we are going to -use [OWASP Zed Attack Proxy](https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project), or ZAP for short. +### Requirement +Continuing with the user account, we should allow the user to change their password. -1. Please download and install ZAP. -2. Run ZAP. It will ask if you want to persist the ZAP Session. -3. Select `No, i do not want to persist this session at this mement in time` and uncheck `Remember my choice and do not ask me again`. -4. Click `Start`. -5. On the top right, find the icon `Open the browser you've chosen in the Quick Start tab pre-configured to proxy trough ZAP`. In my case it had the firefox icon. -6. Navigate to [http://localhost:5000/user/login](http://localhost:5000/user/login) -7. Login with the credentials of the user you created. -8. On `ZAP` go to the `History` tab in the bottom half of the window. -9. Find the `/user/welcome` request. -10. Go to the `Request` tab in the top half of the window. -11. On the header section you can see the cookie being sent like `Cookie: session=eyJrZXkiOiJHSDFWdThPbFdKRExWbU9ZTGY2SkJJMXJ5NUZNRlIwNVhoWTUwanFwZUxRIn0.XXsIUA.nNZ8EN3ty3HfsUjzTrEKZ9mzNPQ` -12. Copy the cookie value. -13. Go ahead and change the password in [http://localhost:5000/user/change_password](http://localhost:5000/user/change_password) -14. Once again click on`Open the browser you've chosen in the Quick Start tab pre-configured to proxy trough ZAP`. In my case it had the firefox icon. -15. In the new browser confirm you are not logged in by going to [http://localhost:5000/user/welcome](http://localhost:5000/user/welcome) -16. You should get redirected to the login page. -17. On `ZAP` click on `Set break on all requests and responses`. Should be a green circle icon. -18. On your unauthenticated browser, go to [http://localhost:5000/user/welcome](http://localhost:5000/user/welcome). -19. On `ZAP` insert the cookie value copied in step 11 in the headers section of the breakpoint. -20. On the top click on `Submit and continue to next break point`. Which will look like a play icon. +### Development +We add a simple form that allows a user to enter their current password and a new password. -As you can see even after the user changed their password, we were able to log in using the session value captured previously successfully performing a session hijacking attack. +*Note*: For simplicity we aren't going to add a repeat your password field, but on a real world scenario you probably should. -**Proceed to [next section](https://github.com/nxvl/secure-coding-with-python/tree/5.2-broken-deauthentication/fix)** +### Vulnerability +Most of the times a user changes their password is because of suspicion of account compromise. If an attacker has already +gotten their hands on the user credentials, changing the password is expected to prevent further access from +the attacker. By changing the password, but not invalidating the `session_key` and attacker can keep their +access to the compromised account, contrary to the user expectations. + +**Proceed to [next section](https://github.com/nxvl/secure-coding-with-python/tree/5.2-broken-deauthentication/test)** ## Index ### 1. Vulnerable Components