top of page
  • 5.15 Technologies

Django Session Security: Handling Session Timeouts and Expirations

Web application security is of utmost importance in today's digital landscape, and session management is a critical aspect of it. Django, a widely used web framework, provides a robust session management system out of the box. However, handling session timeouts and expirations correctly is still crucial to protecting user data from security breaches. Fortunately, the Django-session-security Python library can help developers set up and manage session timeouts and expirations more efficiently. So, with that all being said, let’s jump in and discuss the importance of session security in your Django application!


Why Is Session Security Important?

Session security for timeouts and expirations is crucial in any web application development, including Django applications. It helps protect sensitive user data from unauthorized access and misuse. In Django, a session is a mechanism that allows the application to store user data temporarily between HTTP requests, such as user authentication status, user preferences, and shopping cart items, among others. Without proper session management, malicious actors can exploit vulnerabilities in the session management process to hijack user sessions, steal sensitive data, or carry out attacks such as cross-site scripting (XSS) and cross-site request forgery (CSRF).


Session timeouts are essential for terminating inactive sessions after a predetermined period of inactivity. For instance, if a user logs into a web application but remains inactive for an extended period, their session should expire after a specified duration to prevent unauthorized access. This feature is particularly important in public or shared environments, such as internet cafes or public computers, where users may leave their sessions active even after they leave.


Session expirations are another critical feature of session management that helps protect user data. When a session expires, it means that the session data is no longer valid, and the user must log in again to access their data. Session expirations are useful for preventing attackers from reusing old sessions or stealing session data, as an expired session is essentially useless.


Setting Up Session Security in Django

Now that we’ve covered a little bit about what session security can provide for our Django application, let’s start diving into how we can implement it into our sample application, which is the Django Sample Application. This implementation builds on top of the LDAP branch which configured LDAP authentication for our Django application. The branch for this article can be located below:

To start adding session security to our Django application, we’ll need to add the Django-session-security Python library to our environment. We can do this by updating our requirements.txt file, as seen below.

Django~=3.2.16
python-dateutil~=2.8.2
urllib3~=1.26.12
requests~=2.28.1
djangorestframework~=3.14.0
drf-yasg~=1.21.4
django-python3-ldap~=0.15.4
django-session-security~=2.6.7

Next is settings. There are a few configuration changes needed in the settings.py file to get the session security working. One of those is the INSTALLED_APPS variable, which adds the “session_security” app.

INSTALLED_APPS = [
    'app',
    'api',
    'rest_framework',
    'personnel',
    'drf_yasg',
    'django_python3_ldap',
    'session_security',
    … TRUNCATED
]

The MIDDLEWARE variable also needs to be updated, as seen below. The new entry needed is session_security.middleware.SessionSecurityMiddleware.

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware', 
    … TRUNCATED
    'session_security.middleware.SessionSecurityMiddleware',
]

The last change needed in the settings.py file is to include some custom variables defined in the Django-session-security Python library. More information about available variables can be found here. The settings that we define are outlined below. Each variable serves its own purpose:

  • SESSION_SECURITY_WARN_AFTER – This will warn a user that their session is about to expire.

  • SESSION_SECURITY_EXPIRE_AFTER – This sets a timeout for a user’s session. If the session is inactive for the defined amount of time, the session is timed out and expires.

  • SESSION_EXPIRE_AT_BROWSER_CLOSE – This does exactly what you think. As soon as the browser is closed, the session expires. When the user navigates to the URL again, they are prompted to log in.

SESSION_SECURITY_WARN_AFTER = 29 * 60
SESSION_SECURITY_EXPIRE_AFTER = 30 * 60
SESSION_EXPIRE_AT_BROWSER_CLOSE = True

The next file that needs to be updated is the urls.py file in the “demoapp” app. This file needs to include the session security URLs in the root urls.py file of the Django project. The new urls.py file is configured as follows.

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('personnel.urls')),
    path('', include('app.urls')),
    path('', include('api.urls')),
    re_path(r'session_security/', include('session_security.urls'))

]

The last file that needs updating is the base.html file that will implement the popup for inactive sessions. This change just requires an include statement from the session security Python library as seen below.

{% include 'session_security/all.html' %}

This is best added in your base HTML file that is used for all your other Django templates. It will need to be included after loading jQuery in your HTML. Also, depending on how your application is deployed, you may need to execute the following command to make sure all the proper static files are in place.

python manage.py collectstatic

Now that we have the Django settings and URL patterns set up, we will look at the login page configuration in the next section.


Testing Session Security

To properly test the session security is working as expected, we first need to implement a login page. This login page will be shown to the user as soon as they navigate to the website and will be required before accessing anything on the site. All configurations for the login page are included in the “app” app, including the two new files, login.html and auth.py. The HTML file will serve the login prompt whereas the auth.py file will handle validating authentication and checking session validity. The classes defined in the auth.py file are outlined below.

class AuthUserMixin(LoginRequiredMixin, UserPassesTestMixin):
    def test_func(self):
        return self.request.session.get('is_authenticated', False)

    def handle_no_permission(self):
        self.request.session['next_url'] = self.request.build_absolute_uri()
        return redirect('login')

class UserLoginForm(AuthenticationForm):
    def __init__(self, *args, **kwargs):
        super(UserLoginForm, self).__init__(*args, **kwargs)

    username = UsernameField(widget=forms.TextInput(
        attrs={'class': 'form-control', 'placeholder': 'Username', 'id': 'username'}))
    password = forms.CharField(widget=forms.PasswordInput(
        attrs={
            'class': 'form-control',
            'placeholder': 'Password',
            'id': 'password',
        }

))

The purpose of each class is defined as follows:

  • AuthUserMixin – This class is used in conjunction with a View class to require authentication for that view. It will check for a valid session and if none are found, it will automatically redirect the user to the login page.

  • UserLoginForm – This class defines the login form that is going to be used by the login.html file when loaded.

The last two files that are updated include views.py and urls.py. The views.py file includes a new class that will serve the login page and defines the login form created in the auth.py file, as seen below.

class CustomLogin(views.LoginView):
    template_name = "app/login.html"
    authentication_form = UserLoginForm

    def form_valid(self, form):
        login(self.request, form.get_user())
        self.request.session['is_authenticated'] = True
        return HttpResponseRedirect(self.get_success_url())

After configuring the view, the urls.py URL patterns can be updated as follows.

urlpatterns = [
    path('', views.Index.as_view(), name='index'),
    path('login', views.CustomLogin.as_view(), name='login'),
]

Lastly, the AuthUserMixin class will need to be added to each class that you want to enforce authentication on, as such.

class Index(AuthUserMixin, TemplateView):
    template_name = 'personnel/index.html'

With all the changes in place, when we navigate to http://{IP}:8000/ we are prompted to log in as seen in the below image.

Django Sample Application

After logging in, the session security library will check for inactivity and will prompt when a session is about to expire. Once the session has expired, it will log the user out and require you to log back in. The prompt that is shown can be updated using the steps outlined in the documentation linked previously.

Session Timeouts and Expirations

Conclusion

Proper session management is a critical aspect of web application security, and Django-session-security is an excellent Python library for enhancing session security in Django. With its robust set of features and settings, this package allows developers to set up and manage session timeouts and expirations more efficiently. From terminating inactive sessions to disconnecting sessions on browser closure, it can give you peace of mind that sessions are not being left open for an extended period. Take some time to get these settings in your Django application to provide a better platform for your organization and users!


Thank you for taking the time to review this article on Django session security and handling session timeouts and expirations. We hope this information has been valuable in enhancing the security of your web applications. If your project requires more advanced capabilities or if you have any questions, please don't hesitate to contact us.


5.15 Technologies is here to support you!


bottom of page