Anton Alekseev for PyCon Estonia 2020
Technical Lead and Fullstack Developer @ Thorgate
Not a Security Expert -
But inspired enthusiast
Famous Breaches in 2020
100% Secure Web-Application
Image from Pixabay
Misconceptions about security
Misconceptions about security
Me, trying to read about cryptography
Django has a reputation of a very secure framework
Misconceptions about security
for more secure applications
Me, looking at all requests that my application is making
(for everything)
With HTTP connection you don't even need to spoof certificate
(Howto fix)
for more secure applications
"I will just set this option to True"
(with security in mind)
How much information can we get from Django debug page?
(Howto fix)
$ python 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.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.W018) You should not have DEBUG set to True in deployment.
?: (security.W020) ALLOWED_HOSTS must not be empty in deployment.
System check identified 6 issues (0 silenced).for more secure applications
Well well well, they left keys in the engine
2 600 000 results on GitHub containing "secret key"
(Howto fix)
for more secure applications
Your application, still running on
Django 1.4 - did they forgot about me?
(Howto fix)
(venv) ➜ django_app safety check --full-report
+==============================================================================+
| REPORT |
| checked 40 packages, using default DB |
+============================+===========+==========================+==========+
| package | installed | affected | ID |
+============================+===========+==========================+==========+
| insecure-package | 0.1.0 | <0.2.0 | 25853 |
+==============================================================================+
| This is an insecure package with lots of exploitable security |
| vulnerabilities. |
+==============================================================================+
| django | 1.11 | <1.11.19,>=1.11.0 | 36885 |
+==============================================================================+
| Django 1.11.x before 1.11.19 allows Uncontrolled Memory Consumption via a |
| malicious attacker-supplied value to the django.utils.numberformat.format() |
| function. |
+==============================================================================+for more secure applications
Your admin username is admin and you will be hacked soon
(Example)
https://secret-base.com/admin/
admin@secret-base.com
(Improvements)
for more secure applications
When framework provides you with tools, but you like - nope, can't see anything
for more secure applications
Use professional tools to destroy the illusion that you application is secure
for more secure applications
Not All users are nice
(XSS - Cross Site Scripting)
(XSS Example)
<!-- BAD -->
{% for comment in article_comments %}
<div class="comment">
<div class="user">{{ comment.author | default: "Anonym" }}</div>
<div class="content">{{ comment.raw_html | safe }}</div>
</div>
{% endfor %}<!-- BETTER -->
{% for comment in article_comments %}
<div class="comment">
<div class="user">{{ comment.author | default: "Anonym" }}</div>
<!-- Note that we removed UNsafe "safe" filter -->
<div class="content">{{ comment.raw_html }}</div>
</div>
{% endfor %}(XSS Prevention)
(SQLi - SQL Injection)
No security talk should be without this classical comics
(SQLi Example)
# Malicious SQL code will return all rows from the
# DB table regardless of initial filter in your SQL code
user_input = '"" or 1 = 1;--'
# BAD
# Note that we are formatting the string here, before passing it to Django
Customers.objects.raw(
f'SELECT * FROM Customers WHERE customer_name = {user_input}'
)# Malicious SQL code will return all rows from the
# DB table regardless of initial filter in your SQL code
user_input = '"" or 1 = 1;--'
# BETTER
# Note that here we passing malicious output to the Django,
# rather than formatting the SQL code ourself.
# Postgres is smart enough to escape malicious input and not evaluate it.
Customers.objects.raw(
'SELECT * FROM Customers WHERE customer_name = %s',
[user_input]
)(SQLi Prevention)
for more secure applications
Are you storing personal data in plain text?
(by requesting only what necessary)
(examples)
# BAD
# Lazy code - exposes everything from the database table
class UserProfileSerializer(serializers.ModelSeriazlier):
class Meta:
model = UserProfile
fields = "__all__"# BETTER
class UserProfileSerializer(serializers.ModelSeriazlier):
class Meta:
model = UserProfile
# Note that we explicitly saying which data will
# be exposed in the application API
fields = ("profile_pic", "job_title")(preventing)
Django nor any automated tool can protect you from making mistakes here.
However these basic things can help:
for more secure applications
That is one good role model for authorization system
Image from ssl2buy wiki
(Examples)
# BAD
# Only checking that user is authenticated
def transfer_money_view(request):
if not request.user.is_authenticated:
raise PermissionDenied
form = TransferMoneyForm(request.GET or request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse("home"))# BETTER
# With a check that user can perform action
def transfer_money_view(request):
if not request.user.is_authenticated:
raise PermissionDenied
if user.name == "Al Capone":
raise PermissionDenied
form = TransferMoneyForm(request.GET or request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse("home"))(Preventing)
for more secure applications
Step 0
Special kudos for my colleagues
Madis Peetersoo & Karl Õkva
for support and guidance