portal_review/notes.md

148 lines
7.4 KiB
Markdown

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.
4. 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. For example for 2.2, the known vulnerabilities in Django are: https://snyk.io/vuln/pip:Django@2.2. I would recommend to verify that the project's code does not have any of these.
## 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
```