Skip to content
Open
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
# Secure Coding with Python.

## Chapter 2: SQL Injection
### Fix part 3
An even better approach is to use an ORM, in this case we set up SQLAlchemy, by using the standard methods the ORM will do the sanitization so we don't need to worry about it.
## Chapter 3: Weak Password Storage
### Requirement
Now that we know our DB is working, it's time to start creating some users. We should have a signup account that create the user.

**Note**: Most ORMs in some special use cases can still allow SQL Injections to happen, if you are using non-standard methods, review the ORMs security guidelines and test your application.
### Development
We create a signup page, a user model and start taking in new users.

**Proceed to [next section](https://github.com/nxvl/secure-coding-with-python/tree/3.1-weak-password-storage/code)**
### Vulnerability
Since we are not thoughtful on what we are doing, we are storing the passwords in plain text. Meaning anyone with access to our DB, or exploiting an SQL injection, as shown in previous chapter, can easily get any user password.

**Proceed to [next section](https://github.com/nxvl/secure-coding-with-python/tree/3.1-weak-password-storage/fix)**

## 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 @@ -25,7 +25,8 @@ def create_app(test_config=None):
db.init_app(app)
migrate.init_app(app, db)

from . import listings
from . import listings, users
app.register_blueprint(listings.bp)
app.register_blueprint(users.bp)

return app
7 changes: 7 additions & 0 deletions marketplace/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
from . import db

class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
full_name = db.Column(db.String(100))
email = db.Column(db.String(100))
password = db.Column(db.String(100))

class Listing(db.Model):
__tablename__ = 'listings'

Expand Down
17 changes: 17 additions & 0 deletions marketplace/templates/users/signup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{% extends 'base.html' %}

{% block header %}
<h1>{% block title %}Create new user{% endblock %}</h1>
{% endblock %}

{% block content %}
<form method="post">
<label for="full_name">Full Name</label>
<input name="full_name" id="full_name" required>
<label for="email">Email</label>
<input name="email" id="email" required>
<label for="password">Password</label>
<input type="password" name="password" id="password" required>
<input type="submit" value="Signup">
</form>
{% endblock %}
9 changes: 9 additions & 0 deletions marketplace/templates/users/signup_success.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% extends 'base.html' %}

{% block header %}
<h1>{% block title %}Successful user creation{% endblock %}</h1>
{% endblock %}

{% block content %}
Successfully created user for {{ user.full_name }} with email {{ user.email }}
{% endblock %}
20 changes: 20 additions & 0 deletions marketplace/users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from flask import Blueprint, request, render_template

from . import db
from .models import User

bp = Blueprint('users', __name__, url_prefix='/user')

@bp.route('/signup', methods=('GET', 'POST'))
def sign_up():
if request.method == 'POST':
user = User(
full_name=request.form['full_name'],
email=request.form['email'],
password=request.form['password'],
)
db.session.add(user)
db.session.commit()

return render_template('users/signup_success.html', user=user)
return render_template('users/signup.html')
34 changes: 34 additions & 0 deletions migrations/versions/67168ab4efaa_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""empty message

Revision ID: 67168ab4efaa
Revises: d018d799acf7
Create Date: 2019-07-19 12:26:57.013800

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '67168ab4efaa'
down_revision = 'd018d799acf7'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('users',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('full_name', sa.String(length=100), nullable=True),
sa.Column('email', sa.String(length=100), nullable=True),
sa.Column('password', sa.String(length=100), nullable=True),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('users')
# ### end Alembic commands ###