portal_review/notes.md

7.2 KiB

I divide the security points that I think are important into 3 classes: 1) Critical and 2) Other based on their importance and django recommendations.

Critical points

  1. DB Password in codebase

  2. SECRET_KEY in codebase and same in development and production

  3. Object level access control permission missing

  • I see the UserPermission class and I am assuming it is for managing object level permission but I am not sure how it is being used for object level permissions. By object permissions, I mean granting add/delete/change/view permissions on an object to a particular user or a group.
  • In Django we generally use the django-guardian module to accomplish this. https://django-guardian.readthedocs.io/en/stable/
  • Each object can be assigned permission specifically to a user or a group

For eg. the following (taken from https://django-guardian.readthedocs.io/en/stable/userguide/assign.html#assign-obj-perms)

    >>> from django.contrib.auth.models import User
    >>> boss = User.objects.create(username='Big Boss')
    >>> joe = User.objects.create(username='joe')
    >>> task = Task.objects.create(summary='Some job', content='', reported_by=boss)
    >>> joe.has_perm('assign_task', task)
    False

    >>> from guardian.shortcuts import assign_perm
    >>> assign_perm('assign_task', joe, task)
    >>> joe.has_perm('assign_task', task)
    True

The following code taken from payroll/views.py file lines 1119-1137

@login_required
def attachment_delete(request, pk):
    """
    Attachment löschen
    """
    # Attachment auswählen
    instance = Attachment.objects.get(id=pk)
    # Dateipfad ermitteln
    file_path = str(instance.attachment)
    # Physische Datei löschen
    try:
        os.remove(os.path.join(MEDIA_ROOT, file_path))
    except:
        pass
    # Instanz löschen
    instance.delete()

    # zurück zur Ursprungsseite
    return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))

Anyone who can login to the system, could potentially delete an attachment belonging to some other user, which may be disastrous. We could easily overcome this like the example from django-guardian above.

  1. I am not sure what exact Django version the app is designed for. I am assuming some version of Django 2.x.x. based on my attempt to run the project. It would be nice to check all vulnerabilities for this specific version of Django.

Standard Django app deployment checks

  • Check issues in manage.py check --deploy
(venv) [pcoder@archlinux portal]$ ./manage.py check --deploy
System check identified some issues:

WARNINGS:
?: (security.W004) You have not set a value for the SECURE_HSTS_SECONDS setting. If your entire site is served only over SSL, you may want to consider setting a value and enabling HTTP Strict Transport Security. Be sure to read the documentation first; enabling HSTS carelessly can cause serious, irreversible problems.
?: (security.W006) Your SECURE_CONTENT_TYPE_NOSNIFF setting is not set to True, so your pages will not be served with an 'x-content-type-options: nosniff' header. You should consider enabling this header to prevent the browser from identifying content types incorrectly.
?: (security.W007) Your SECURE_BROWSER_XSS_FILTER setting is not set to True, so your pages will not be served with an 'x-xss-protection: 1; mode=block' header. You should consider enabling this header to activate the browser's XSS filtering and help prevent XSS attacks.
?: (security.W008) Your SECURE_SSL_REDIRECT setting is not set to True. Unless your site should be available over both SSL and non-SSL connections, you may want to either set this setting True or configure a load balancer or reverse-proxy server to redirect all connections to HTTPS.
?: (security.W012) SESSION_COOKIE_SECURE is not set to True. Using a secure-only session cookie makes it more difficult for network traffic sniffers to hijack user sessions.
?: (security.W016) You have 'django.middleware.csrf.CsrfViewMiddleware' in your MIDDLEWARE, but you have not set CSRF_COOKIE_SECURE to True. Using a secure-only CSRF cookie makes it more difficult for network traffic sniffers to steal the CSRF token.
?: (security.W019) You have 'django.middleware.clickjacking.XFrameOptionsMiddleware' in your MIDDLEWARE, but X_FRAME_OPTIONS is not set to 'DENY'. The default is 'SAMEORIGIN', but unless there is a good reason for your site to serve other parts of itself in a frame, you should change it to 'DENY'.

Actions to take for the warnings above

Preventing XSS https://docs.djangoproject.com/en/3.0/topics/security/

As it looks like the project is on a Django version less that 3.0, setting SECURE_CONTENT_TYPE_NOSNIFF to True is recommended. This will add X-Content-Type-Options: nosniff header to all requests ensuring that browsers will not be able to guess the content type of the served resource.

SECURE_CONTENT_TYPE_NOSNIFF=True

Setting SECURE_BROWSER_XSS_FILTER to True is recommended. This adds X-XSS-Protection: 1; mode=block header on all responses. This tells the browsers to block content that look like XSS attack. This works on old browsers only.

SECURE_BROWSER_XSS_FILTER=True

Preventing clickjacking https://docs.djangoproject.com/en/3.0/ref/clickjacking/

Enable XFrameOptionsMiddleware middleware and set X_FRAME_OPTIONS to DENY if you are not using iframes at all. If you intend to use it then set this value to SAMEORIGIN which will allow the iframes to be embedded in your page which are served from the same domain. It is supported by most modern browsers (not all)

X_FRAME_OPTIONS=DENY

Preventing CSRF https://docs.djangoproject.com/en/3.0/ref/csrf/

I think almost all forms in the project use {% csrf_token %} which is good.

Use sessions instead of cookies https://docs.djangoproject.com/en/3.0/ref/settings/#csrf-use-sessions

Django stores the CSRF token in cookie by default. Though this should be sufficient, storing in sessions is opted more often as a standard practice. Hence, to turn on session enable the following setting

CSRF_USE_SESSIONS=True

If you still prefer to go with cookies, ensure that the following is set to True which will make sure that the csrf token is always exchanged over https

SESSION_COOKIE_SECURE=True

There is a whole lot of things to look into when looking into CSRF in details. Please refer https://docs.djangoproject.com/en/3.0/ref/csrf/#using-csrf for more info.

Exchanging data exclusively over https https://docs.djangoproject.com/en/3.0/topics/security/#ssl-https

This is a standard recommendation for all websites nowadays.

If all the traffic of the site is meant to be via ssl and exempt certain urls using SECURE_REDIRECT_EXEMPT if necessary OR another option is to handling this via an app server (nginx or apache).

SECURE_SSL_REDIRECT=True

Exempting any urls or regex from being redirected via ssl https://docs.djangoproject.com/en/3.0/ref/settings/#secure-redirect-exempt

SECURE_REDIRECT_EXEMPT = []

When this setting is set to True, all non-https requests will be redirected to the domain specified by SECURE_SSL_HOST below.

SECURE_SSL_REDIRECT = True

Use the name of the domain that will handle https requests. This has effect only when SECURE_SSL_REDIRECT is set to True.

SECURE_SSL_HOST=ssl.mydomain.com