CM3035 Topic 08: User Authentication and Security
:ID: a9098ba6-4ddb-4768-b8bb-1bc64652b09a
Main Info
Title: User Authentication and Security
Teachers: Daniel Buchan
Semester Taken: April 2022
Parent Module: cm3035: Advanced Web Development
Description
Auth and stuff.
Key Reading
Attacks
Protection
HTTPS
Vulnerability Diagnostics
Authentication
Lecture Summaries
8.1 Attacks
Cross Site Scripting (XSS)
XSS is a code injection attack. The attacker wants to run malicious JS on a target’s machine. To do this, they add it to a benign/trusted site, that unwittingly hosts the code.
There are stored and reflected variations of XSS.
Stored XSS attacks
here js is stored remotely, on the benign website. For example if the site is a forum, or includes comments, the user can post a piece of malicious js as a comment, and it will then be stored in the server.
When a second client comes to fetch the comments, they do so trusting the site, but if the site is badly set up that script might then execute on page render.
Reflected XSS attacks
Here the attack is via a non-direct route. generally there would be a link from a non-direct source - for example in an email, or link on a malicious website, the link contains code to execute and it sent to a legitimate site.
The legitimate site raises a response (error) which contains the data/script.
Client sees response is from a legitimate site and executes the code.
IE the attack vector here is that the response comes from a legit site, but includes the original bad script/data from the malicious site. this might then execute.
To prevent, we just have to sanitize input. In a stored case, we sanitize all input before storing to the db. In a reflected case, we must ensure all responses do not contain code.
8.104 CORS
Cross-Origin Resource Sharing (or CORS) is a means to work around browser default policies around resource origins.
Browsers typically enforce a Same Origin Policy. When I load a page from one domain, the returned resources (html, js) are only allowed to fetch resources from the same domain.
CORS settings allow us to set things up such that web applications are allowed to share resources to circumvent this restriction. EG they let us host our files, images etc on different servers to our html and js.
It allows our clients to make API requests to resources that are not on the API source domain.
CORS attacks are possible when we misconfigure the settings.
We can end up exposing resources that are not meant to be shared, like APIs, fonts, images.
there are two settings that we can misconfigure to expose ourselves to this:
Access-Control-Allow-Origin
we should whitelist domains
do not wildcard
do not set as null
Access-Control-Allow-Credentials
do not set as null
prevents use of wildcards in Allow-Origin for credentialled requests.
8.107 Denial of Service
DoS or DDoS (distributed version) is an attempt to take a resource/site offline.
Commonly the pattern is to flood the server with requests, which eventually blocks access for legitimate users.
You might have the site allocate too many resources - if you saturate the system threads it can’t run more, or you could overload its memory.
Or you force the server not to release resources - keep connections open.
or you might try to upload loads of data to force it to run out of storage space.
To remediate these we might increase resources - bigger disks/dbs, more servers, CDN.
8.110 Buffer Overflow
Common attack for many types of software, including servers.
An attempt to crash a running process, or use the process to execute malicious code.
One means is by sending too much data to some input, if the input length is not checked the data might write over memory when it should not be. This might cause a crash or insert code into memory which is then executed.
Mitigation: We ensure buffers are sufficient length, we sanitise inputs, check lengths of input data.
8.113 SQL Injection
An attempt to submit data via a service from an untrusted source.
Data will cause malicious SQL to run in the application.
Read, dump or send database contents, or destroy a datastore
Execute commands with higher privileges or even unix terminal access
Common attack on PHP and ASP
Remediation: sanitise all inputs. Construct SQL programmatically (eg use ORM), never execute user inputs. Ensure database runs with a low privileged user.
8.118 Cross Site Request Forgery (CSRF)
Attempt to trick a user into sending a malicious request
User is authenticated legitimately
User follows a link provided by an illegitimate source that will send malicious data into our application.
Solutions: Set CORS policies correctly.
Forms have a per-request form-key that identifies the form is legitimately from our website.
Users ensure they are logged out of sites when they finish. Expiry time for auto-logout.
8.119 Clickjacking
This is the UI redress attack.
An attempt by the attacker to insert a ‘layer’ between the user and legitimate site.
The attacker can use the layer to capture user events (eg keystrokes, mouse actions)
The attacker passes it through to the website so the attack is invisible.
Typically uses an HTML frame to load a transparent layer.
To defend against it we can set the servers’ Content Security Policy frame ancestors directive to not allow framing. Ensure UI is sitting at the top level, not nested in frames.
8.2 Making Sites Secure
8.201 Web app built in security
Most modern web frameworks provide built in security features:
xss protection - we can use Django templating here, which will escape where possible.
Templating won’t always help though, let’s say we have a <div class='{{var}}'>
. Then the user manages to set var to 'class1 onclick=javascript:malicious_function()'
then the result will be <div class=class1 onlclick=javascript:malicious_function()
.
So you need to check user input.
csrf protection - enable csrf middleware, ensure {%csrf_token()%}
is included in all forms, this ensures all form submissions have a unique token.
sql injection protection - model querysets are safe from incoming SQL, minimize use of raw, custom sql. Sanitise any user inputs of raw, custom sql.
clickjacking protection - enable x-frame-options middleware, ensure sites can not be rendered inside third-party site.
HTTPS
HTTPS is the cryptographically secure extension of HTTP. All HTTP messages are encrypted, making use of TLS (Transport Layer Security) that requires a third party certificate authority.
TLS is a means of encrypting data that runs over a reliable transport protocol (typically TCP).
The rough outline is:
Client issues a secure connection request
Server agrees and returns a certificate
Client checks certificate validity with Certificate Authority
Session keys exchanged
Communication starts
In HTTPS all components of HTTP can be transmitted over TLS. It’s convenient in that only one party needs to be signed (the server). It’s secure against eavesdropping and man-in-the-middle attacks.
It does not seure IP address or port numbers (in the IP wrapper). Uses port 443 rather than 80.
OWASP
The OWASP foundation is an online developer-led community. In existence since 2001. Founded by Mark Curphey, provides documentation, guidance and research.
There are ‘projects’, which are member-led initiatives on web security. There will be some documentation, code, and tools for some issue in security. Most cities have an OWASP chapter, with hackathons, talks etc.
Best practices
Pathching and updating: most code contains bugs, approx one bug per 100 lines of production code. Some bugs present security holes. This is true of your code, your framework, its language and so on.
Patches keep your code environment up to date, keep your packages/libraries up to date.
We can check the Django docs about security:
https://docs.djangoproject.com/en/dev/internals/security/
https://groups.google.com/forum/#!forum/django-users
https://github.com/django/django
also the equivalents for drf:
https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework
https://github.com/encode/django-rest-framework/security
8.3 Django Authentication and Administration
Authentication is a process by which we can verify the identity of a user.
We shall restrict content/resources access for users according to their identity
The Django authentication system is provided by the django.contrib.auth
application.
It requires SessionMiddleware
and AuthenticationMiddleware
to be enabled in settings (they are by default).
Now we can have differently identified sets of users, resource permission flags, user groups, configurable password hashing, all forms and pages for user registration, log in and log out.
It does not provide password safety checks, no login throttling, no third-party authentication authorities. We need different modules to add these features.
8.4 Django application authentication
Runs through setting up user auth on a django project.
Start by adding a model for your users:
from django.db import models
from django.contrib.auth.models import User
class AppUser(models.Model):
user = models.oneToOneField(User, on_delete=models.CASCADE)
organisation = models.CharField(max_length=256, null=True, blank=True)
def __unicode__(self):
return self.user.username
Register the model with the admin interface, and add the forms for logging in:
from django.forms import ModelForm
from django.contrib.auth.models import User
from .models import *
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'email', 'password')
class UserProfileForm(ModelForm):
class Meta:
model = AppUser
fields = ('organisation',)
Then we can implement the view:
def register(request):
registered = False
if request.method == 'Post':
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.set_password(user.password) # don't store in plain text
user.save()
profile = profile_form.save(commit=False)
profile.user = user
if 'organisation' in user_form.cleaned_data:
profile.organisation = request.DATA['organisation']
profile.save()
registered = True
else:
user_form = UserForm()
profile_form = UserProfileForm()
return render(request, 'genedata/register.html', {'user_form': user_form,
'profile_form': profile_form,
'registered': registered,
}
Then you can create a template that responds to the registered status:
{% extends "./base.html" %}
{% block content %}
<h1>Register</h1>
{% if registered %}
<strong> Thank you for registering </strong>
{% else %}
<strong> Register Here </strong> <br />
<form id="user_form" method="post", action="/register/"
enctype="multipart/form-data">
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<input type="submit" name="submit" value="Register" />
</form>
{% endif %}
{% endblock %}
Now we can write a function to handle a login action:
from django.contrib.auth import authenticate, login
from django.http import HttpResponseRedirect
def user_login(request):
if request.method == 'POST':
username=request.POST['username']
password=request.POST['password']
user = authenticate(username=username, password=password)
if user:
if user.is_active:
login(request, user) # sends cookie to browser with login creds
return HttpResponseRedirect('/') # to home page
else:
return HttpResponse('Your account is disabled')
else:
return HttpResponse('Invalid login')
else:
return render(request, 'genedata/login.html, {})
8.404 second half shows the login form that corresponds to this.
8.405 shows logging out, which is a simple function provided by the django.contrib.auth
module.
8.406 covers access control. Here’s how we can restrict users for some arbitrary view:
def some_view(request):
if not request.user.is_authenticated():
return ("You are not logged in")
else:
return ("You are logged in")
Or we can control access to entire functions with decorators:
from django.contrib.auth.decorators import login_required
@login_required
def user_logout(request):
logout(request)
return HttpResponseRedirect('/')
What about class views?
Here we need to go to the urls instead and control access to the routing via the decorator.
from django.contrib.auth.decorators import login_required
urlpatterns = [
path('gene/<int:pk>', login_required(login_url='login/')(views.GeneDetail.as_view()), name='gene_datail'),
]