Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
3 changes: 2 additions & 1 deletion marketplace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -29,4 +30,4 @@ def create_app(test_config=None):
app.register_blueprint(listings.bp)
app.register_blueprint(users.bp)

return app
return app
23 changes: 23 additions & 0 deletions marketplace/templates/users/change_password.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{% extends 'base.html' %}

{% block header %}
<h1>{% block title %}Change your password{% endblock %}</h1>
{% endblock %}

{% block content %}
Hello <b>{{user.full_name}}</b>, please enter your current password and the new one you want to use:

{% if msg %}
<p>{{msg}}</p>
{% endif %}

<form method="post">
<label for="current_password">Current Password</label>
<input type="password" name="current_password" id="current_password" required>
<br/>
<label for="new_password">New Password</label>
<input type="password" name="new_password" id="new_password" required>
<br/>
<input type="submit" value="Change Password">
</form>
{% endblock %}
4 changes: 2 additions & 2 deletions marketplace/templates/users/welcome.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ <h1>{% block title %}Welcome{% endblock %}</h1>
{% endblock %}

{% block content %}
<a href="/user/logout">Logout</a><br/>
Welcome to the marketplace!
<a href="/user/logout">Logout</a>&nbsp;&nbsp;<a href="/user/change_password">Change Password</a><br/>
Welcome <b>{{user.full_name}}</b> to the marketplace!
{% endblock %}
16 changes: 15 additions & 1 deletion marketplace/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,18 @@ def logout(user):
@bp.route('/welcome', methods=('GET',))
@auth
def welcome(user):
return render_template('users/welcome.html')
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)