Basics of web development

Login, session management and access management

Easy
45 min

Authentication, session management, and access control are important components of web application security. Authentication refers to verifying the identity of a user, while session management refers to managing a user's session in a web application. Access control or authorization refers to not allowing a user to perform actions or access data for which they do not have permission. Here is a brief explanation of how these functions work in web applications:

Authentication:

  1. The user enters their username and password on the login page of the web application.
  2. The web application receives the data and checks whether they match the stored user information.
  3. If the information is correct, the web application allows the user to log in and creates a session associated with the user's data.
  4. If the information is incorrect, the user will receive an error message and will be redirected back to the login page.

Authentication in practice

When a user logs in to a web application with a username and password, the web application compares the user's input data to the stored data in the database. The database contains user information, such as username, password, and other user details.

Password Hashes

It is important that the password is not stored in the database as is, but rather a hash is created from the password and stored in the database. A hash is a one-way function that transforms the password into a random-looking string that cannot be reversed back to its original form. This means that the actual password is not stored in the database, only its hash.

When the user enters a username and password on the login page of the web application, the web application retrieves user data from the database based on the username. Then, the web application uses a hash function to compare the password entered by the user with the hash value stored in the database. If the hash values are the same, the password entered by the user is correct and the user can log in.

This is essential, because if passwords were stored as they are in the database, hackers could directly steal users' passwords from the compromised database and easily misuse them.

Session Management:

  1. When the user logs in, the web application creates a session that is unique to the user.
  2. The session includes user information such as username and location, as well as information about the session's status, such as the time when the user last interacted with the web application.
  3. The web application uses a session to verify that the user is still logged in and has the rights to access certain functions or pages.
  4. When the user logs out, the web application deletes the session and the user can no longer use the web application without logging in again.

Session management in practice

Session management in web applications is often implemented using cookies to exchange information between the browser and the server. When a user logs in, the web application creates a session and stores the session identifier (session ID) in a cookie that is sent to the browser.

Each cookie has a name, value, and expiration time, and session management uses the value of the session identifier. When a user moves from one page to another in a web application, the browser sends a cookie to the server, which checks the session identifier and uses it to find the corresponding session user data.

This enables keeping the web application up to date with the user's actions and information throughout the session. When the user logs out, the web application removes the session and cookie, so the user can no longer access the web application without a new login.

About Session Identifier Security

Proper entropy is extremely important for the security of web application session cookies. Session cookies are unique identifiers that are created when a user logs into a web application. Session cookies are used to track the user's activity within the web application during the session.

Entropy describes the amount of randomness in the session cookie value. The more randomness there is in the session cookie value, the harder it is to guess its value. If the session cookie value is predictable or easy to guess, an attacker can simulate the user's session and gain access to the user's personal information.

That's why it is important that the values of session cookies are generated sufficiently randomly and that the value of the session cookie is updated regularly. Additionally, it is important that the value of the session cookie is stored in the user's browser through an encrypted connection so that attackers cannot hijack the session cookie, for example, through network analysis or monitoring of network traffic.

Therefore, the proper entropy is important to prevent attackers from guessing the value of the session cookie and simulating the user's session.

Complete web application

Expanding the previous module's todo application slightly to support multiple users, registration, login, and logout.

Let's also use an external CSS library, which is a ready-made collection of CSS classes. There are many of these libraries, for example, TailwindCSS is popular nowadays. In this example, we used Bootstrap, which is a bit simpler.

Another new thing here is Jinja2 layout templates, where the idea is to create one layout with the site's styles etc., inside which you define the "block" content. Then you can create separate HTML files that use the layout (extends "base.html").

from flask import Flask, render_template, redirect, request, session, url_for
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(__name__)
app.secret_key = 'secret_key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db'
db = SQLAlchemy(app)


class User(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  username = db.Column(db.String(50), nullable=False, unique=True)
  password_hash = db.Column(db.String(100), nullable=False)

  def __repr__(self):
    return f'<User {self.username}>'


class Task(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  description = db.Column(db.String(200), nullable=False)
  completed = db.Column(db.Boolean, nullable=False, default=False)
  user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
  user = db.relationship('User', backref=db.backref('tasks', lazy=True))

  def __repr__(self):
    return f'<Task {self.description}>'


@app.route('/', methods=['GET', 'POST'])
def index():
  if 'username' not in session:
    return redirect('/login')

  if request.method == 'POST':
    task_description = request.form['task']
    user_id = User.query.filter_by(username=session['username']).first().id
    new_task = Task(description=task_description, user_id=user_id)
    db.session.add(new_task)
    db.session.commit()

  user_tasks = Task.query.filter_by(user_id=User.query.filter_by(
    username=session['username']).first().id).all()
  return render_template('index.html', tasks=user_tasks)


@app.route('/login', methods=['GET', 'POST'])
def login():
  if 'username' in session:
    return redirect('/')
  error = None
  if request.method == 'POST':
    username = request.form['username']
    password = request.form['password']
    user = User.query.filter_by(username=username).first()
    if user and check_password_hash(user.password_hash, password):
      session['username'] = username
      print("SETTING SESSION")
      print(session)
      return redirect('/')
    else:
      error = 'Wrong username or password'
  return render_template('login.html', error=error)


@app.route('/signup', methods=['GET', 'POST'])
def signup():
  if 'username' in session:
    return redirect('/')
  error = None
  if request.method == 'POST':
    username = request.form['username']
    password = request.form['password']
    password_confirmation = request.form['password_confirmation']

    if not username:
      error = 'User ID is required'
    elif not password:
      error = 'Password is required'
    elif password != password_confirmation:
      error = 'Passwords do not match'

    elif User.query.filter_by(username=username).count() > 0:
      error = 'The username is already in use'
    else:
      new_user = User(username=username,
                      password_hash=generate_password_hash(password))
      db.session.add(new_user)
      db.session.commit()
      session['username'] = username
      return redirect('/')
  return render_template('signup.html', error=error)


@app.route('/logout')
def logout():
  session.pop('username', None)
  return redirect('/login')


if __name__ == '__main__':
  with app.app_context():
    db.create_all()
  app.run(host='0.0.0.0', port=81)

First, the application creates a Flask application and sets the secret key SECRET_KEY. This key is important for security purposes as it protects the user's session and cookies.

Then we create an SQLite database that contains two tables: User and Task. User contains usernames and passwords, and Task contains tasks added by the user.

The following defines the User class, which inherits from the db.Model class. The class contains three variables: id, username, and password_hash. id is a unique identifier that is automatically created when a new user is added to the database. username is the username, and password_hash is the hash value of the user's password, which is stored in the database.

Then we define the Task class, which also inherits from the db.Model class. The class contains four variables: id, description, complete, and user_id. id is a unique identifier that is created automatically when a new task is added to the database. description is the description of the task, complete indicates whether the task has been completed or not, and user_id indicates which user has added the task.

Next, we define the login page and its functionality. When the user enters their username and password, the application checks that the username and password are correct. If the username and password are correct, the user's name is saved in the session object, and the user is logged into the application. If the username and password are incorrect, an error message is displayed to the user.

Then define the main page of the application, which displays the user's tasks. If the user is not logged in, they are redirected to the login page. If the user is logged in, the application retrieves the user's tasks from the database based on the user_id variable from the Task table. The tasks are displayed to the user in HTML format.

Next, we define the adding functionality of the task. When the user adds a new task, the application creates a new Task object and saves it into the database. The value of the user_id variable is set to the user's id stored in the session. This allows the application to connect the user and the task in the database.

Finally, the user logout function is defined. When the user logs out, the session is removed, and the user is redirected back to the login page.

Authentication and session management work by using cookies. When a user logs in, the application creates a cookie that stores the user's session information. The cookie contains a random key that is long and complex enough to not be easily guessed. When the user navigates to different pages of the application, the cookie is sent along with the request, and the application can use the cookie to find the user's session information. The session is also stored using a session object, which is stored in the server's memory. This means that when a user logs in, their session information is stored in memory so that the application can use it on different pages.

Practice

Click "Open website" to open the application in a separate window, as the login does not work properly in the embedded web view of Replit.

Kokeile itse!

Valitettavasti Replit-palvelu on muuttnut lennosta eikä enää anna suorittaa näitä koodeja suoraan selaimessa. Voit klikata alla olevaa "Open in Replit" linkkiä ja avata koodin Replit-palvelussa. Meillä on työn alla etsiä Replitille korvaaja.

hakatemia pro

Ready to become an ethical hacker?
Start today.

As a member of Hakatemia you get unlimited access to Hakatemia modules, exercises and tools, and you get access to the Hakatemia Discord channel where you can ask for help from both instructors and other Hakatemia members.