Compare commits
3 Commits
5cdf29b883
...
80dd9e0d07
Author | SHA1 | Date |
---|---|---|
|
80dd9e0d07 | 7 years ago |
|
30b8c224c1 | 7 years ago |
|
29eeac4e78 | 7 years ago |
@ -1 +1,4 @@ |
||||
.DS_Store |
||||
.DS_Store |
||||
__pycache__ |
||||
/venv |
||||
db.sqlite3 |
||||
|
@ -0,0 +1,10 @@ |
||||
#!/usr/bin/env python |
||||
import os |
||||
import sys |
||||
|
||||
if __name__ == "__main__": |
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "securityquiz.settings") |
||||
|
||||
from django.core.management import execute_from_command_line |
||||
|
||||
execute_from_command_line(sys.argv) |
@ -0,0 +1,23 @@ |
||||
# Generated by Django 2.0.2 on 2018-02-05 13:50 |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
initial = True |
||||
|
||||
dependencies = [ |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.CreateModel( |
||||
name='LetsEncryptChallenge', |
||||
fields=[ |
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
('challenge', models.CharField(max_length=128)), |
||||
('response', models.CharField(max_length=128)), |
||||
('expiry_date', models.DateTimeField()), |
||||
], |
||||
), |
||||
] |
@ -0,0 +1,7 @@ |
||||
from django.db import models |
||||
|
||||
|
||||
class LetsEncryptChallenge(models.Model): |
||||
challenge = models.CharField(max_length=128) |
||||
response = models.CharField(max_length=128) |
||||
expiry_date = models.DateTimeField() |
@ -0,0 +1,3 @@ |
||||
django |
||||
django-oauth-toolkit |
||||
django-cors-headers |
@ -0,0 +1,116 @@ |
||||
""" |
||||
Django settings for securityquiz project. |
||||
|
||||
For more information on this file, see |
||||
https://docs.djangoproject.com/en/1.6/topics/settings/ |
||||
|
||||
For the full list of settings and their values, see |
||||
https://docs.djangoproject.com/en/1.6/ref/settings/ |
||||
""" |
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) |
||||
import os, sys |
||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__)) |
||||
|
||||
CLOSED = False |
||||
|
||||
# Quick-start development settings - unsuitable for production |
||||
# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/ |
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret! |
||||
SECRET_KEY = 'jk3nd2kj3nd2i30do23dn9283nd' |
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production! |
||||
DEBUG = False |
||||
|
||||
if 'runserver' in sys.argv: |
||||
DEBUG = True |
||||
|
||||
ALLOWED_HOSTS = ['websec.paulwagener.nl'] |
||||
|
||||
|
||||
# Application definition |
||||
|
||||
INSTALLED_APPS = ( |
||||
'django.contrib.admin', |
||||
'django.contrib.auth', |
||||
'django.contrib.contenttypes', |
||||
'django.contrib.sessions', |
||||
'django.contrib.messages', |
||||
'django.contrib.staticfiles', |
||||
'quiz', |
||||
'oauth2_provider', |
||||
'corsheaders', |
||||
) |
||||
|
||||
MIDDLEWARE_CLASSES = ( |
||||
'django.contrib.sessions.middleware.SessionMiddleware', |
||||
'django.middleware.common.CommonMiddleware', |
||||
'django.middleware.csrf.CsrfViewMiddleware', |
||||
'django.contrib.auth.middleware.AuthenticationMiddleware', |
||||
'django.contrib.messages.middleware.MessageMiddleware', |
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware', |
||||
'corsheaders.middleware.CorsMiddleware', |
||||
) |
||||
|
||||
CORS_ORIGIN_ALLOW_ALL = True |
||||
|
||||
ROOT_URLCONF = 'securityquiz.urls' |
||||
|
||||
WSGI_APPLICATION = 'securityquiz.wsgi.application' |
||||
|
||||
# Database |
||||
# https://docs.djangoproject.com/en/1.6/ref/settings/#databases |
||||
|
||||
DATABASES = { |
||||
'default': { |
||||
'ENGINE': 'django.db.backends.sqlite3', |
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), |
||||
} |
||||
} |
||||
|
||||
# Internationalization |
||||
# https://docs.djangoproject.com/en/1.6/topics/i18n/ |
||||
|
||||
LANGUAGE_CODE = 'en-us' |
||||
|
||||
TIME_ZONE = 'UTC' |
||||
|
||||
USE_I18N = True |
||||
|
||||
USE_L10N = True |
||||
|
||||
USE_TZ = True |
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images) |
||||
# https://docs.djangoproject.com/en/1.6/howto/static-files/ |
||||
|
||||
STATIC_URL = '/static/' |
||||
|
||||
PROJECT_PATH = os.path.realpath(os.path.dirname(__file__)) + '/..' |
||||
MEDIA_ROOT = PROJECT_PATH + '/media/' |
||||
|
||||
TEMPLATES = [ |
||||
{ |
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates', |
||||
'DIRS': [PROJECT_PATH + '/templates'], |
||||
'APP_DIRS': True, |
||||
'OPTIONS': { |
||||
'context_processors': [ |
||||
'django.template.context_processors.debug', |
||||
'django.template.context_processors.request', |
||||
'django.contrib.auth.context_processors.auth', |
||||
'securityquiz.settings.closed', |
||||
'django.contrib.messages.context_processors.messages', |
||||
], |
||||
}, |
||||
}, |
||||
] |
||||
|
||||
STATICFILES_DIRS = ( |
||||
PROJECT_PATH + '/static', |
||||
) |
||||
|
||||
def closed(request): |
||||
return {'CLOSED': CLOSED} |
@ -0,0 +1,15 @@ |
||||
from django.conf.urls import include, url |
||||
from django.contrib import admin |
||||
import views |
||||
|
||||
admin.autodiscover() |
||||
|
||||
urlpatterns = [ |
||||
# Examples: |
||||
url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')), |
||||
url(r'^api/hello', views.SecurityApi.as_view()), |
||||
url(r'^sign$', views.sign), |
||||
url(r'^letsencrypt$', views.letsencrypt), |
||||
url(r'^\.well-known/acme-challenge/(.+)', views.letsencrypt_challenge), |
||||
url(r'^(.*)$', views.home, name='home'), |
||||
] |
@ -0,0 +1,20 @@ |
||||
""" |
||||
WSGI config for securityquiz project. |
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``. |
||||
|
||||
For more information on this file, see |
||||
https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ |
||||
""" |
||||
|
||||
import os, sys |
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "securityquiz.settings") |
||||
|
||||
path = '/var/www/security.aardappelschilmesje.nl' |
||||
if path not in sys.path: |
||||
sys.path.append(path) |
||||
|
||||
from django.core.wsgi import get_wsgi_application |
||||
application = get_wsgi_application() |
||||
|
||||
|
@ -0,0 +1,63 @@ |
||||
<!DOCTYPE html> |
||||
<html> |
||||
|
||||
<head> |
||||
<title>Web Application Security</title> |
||||
<link href="/static/css/bootstrap.min.css" rel="stylesheet" type="text/css"> |
||||
<link href="/static/css/bootstrap-responsive.min.css" rel="stylesheet" type="text/css"> |
||||
<link href="/static/css/style.css" rel="stylesheet" type="text/css"> |
||||
<script type="text/javascript" src="/static/js/jquery-2.1.0.min.js"></script> |
||||
<script type="text/javascript" src="/static/js/jquery.base64.min.js"></script> |
||||
<script type="text/javascript" src="/static/js/quiz.js"></script> |
||||
</head> |
||||
|
||||
<body> |
||||
|
||||
<div class="row-fluid"> |
||||
<div class="well span3" id="menu"> |
||||
|
||||
<h5>Web Application Security</h5> |
||||
<ul> |
||||
<li> |
||||
<a href="/sql">SQL Injection</a> |
||||
</li> |
||||
<li> |
||||
<a href="/xss">Cross-site Scripting</a> |
||||
</li> |
||||
<li> |
||||
<a href="/path">Insecure Direct Object References</a> |
||||
</li> |
||||
<li> |
||||
<a href="/wachtwoorden">Wachtwoorden</a> |
||||
</li> |
||||
<!--<li> |
||||
<a href="/oauth">OAuth</a> |
||||
</li>--> |
||||
<li> |
||||
<a href="/certificaten">Certificaten</a> |
||||
</li> |
||||
<!-- <li> |
||||
<a href="/encryptie">Encryptie</a> |
||||
</li>--> |
||||
</ul> |
||||
|
||||
Moeilijkheidsgraad: |
||||
<select id="difficulty"> |
||||
<option value="easy">Hints zichtbaar</option> |
||||
<option value="normal">Hints optioneel</option> |
||||
<option value="hard">Geen hints</option> |
||||
</select> |
||||
|
||||
<p> |
||||
<a href="/vm">Download VM</a> |
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<div id="quiz" class="span8 offset3"> |
||||
{% block content %}{% endblock %} |
||||
</div> |
||||
</div> |
||||
</body> |
||||
|
||||
</html> |
@ -0,0 +1,307 @@ |
||||
{% extends "base.html" %} {% block content %} |
||||
|
||||
<h1>Certificaten</h1> |
||||
|
||||
<p>Bij dit onderdeel gaan we aan de slag met certificaten. De tool die we daarvoor gaan gebruiken is OpenSSL. Dit is een veelgebruikt |
||||
programma waar je vele cryptografische dingen mee kunt doen.</p> |
||||
|
||||
<p>Op Linux en Mac OS X is deze tool al geïnstalleerd, Windows gebruikers moeten deze nog installeren. Als je |
||||
<a href="http://google.nl/?q=openssl+windows+install" target="_blank">zoekt op het internet</a> vindt je verschillende mogelijkheden om dat te doen. Bijvoorbeeld de v.1.1.0f Light versie op |
||||
<a href="http://slproweb.com/products/Win32OpenSSL.html" target="_blank">deze website</a>. Let op dat je dan op de Windows command line het hele pad moet gebruiken in plaats van alleen 'openssl'. |
||||
Bijvoorbeeld: |
||||
<span class="argument">C:\OpenSSL-Win32\bin\openssl.exe</span> |
||||
</p> |
||||
|
||||
<p>Als je bij het gebruik van OpenSSL errors krijgt, probeer dan eerst je command prompt als Administrator te openen. En als |
||||
dat ook niet werkt om het volgende commando uit te voeren:</p> |
||||
|
||||
<code class="terminal">SET OPENSSL_CONF=[pad naar bestand]\openssl.cfg</code> |
||||
|
||||
<hr> |
||||
|
||||
<blockquote>Wie ben jij? En waarom zou ik jou vertrouwen dat je bent wie je zegt dat je bent?</blockquote> |
||||
|
||||
<p>Dat zijn vragen die webbrowsers elke dag moeten beantwoorden. Een site kan wel vinden dat het www.rabobank.nl is, maar daarmee |
||||
weet een browser nog niet zeker dat het ook daadwerkelijk de webserver van de Rabobank is. Misschien zit je eigenlijk te |
||||
communiceren met een server ergens in Rusland van een persoon die maar al te graag je inlogcodes wil weten.</p> |
||||
|
||||
<p>Om dit probleem op te lossen zijn er certificaten bedacht en vastgelegd in de |
||||
<a href="http://en.wikipedia.org/wiki/X.509">X.509</a> standaard. Certificaten zijn kleine bestandjes waarin een identiteit staat beschreven. Dit is bijvoorbeeld een |
||||
certificaat van Paul Wagener:</p> |
||||
|
||||
<img src="/static/img/certificaat.png" class="center-block" style="border: 1px solid black"> |
||||
|
||||
<p>Nu wil jij natuurlijk meteen een eigen certificaat voor jezelf hebben, en dat kan! Met dit alles-in-1 commando maak je een |
||||
certificaat dat helemaal van jou is:</p> |
||||
|
||||
<code class="terminal">openssl req -x509 -nodes -newkey rsa:2048 -keyout sleutel.key -out certificaat.crt</code> |
||||
|
||||
<p>Dit commando doet een paar dingen tegelijk waar we later op terugkomen. Nadat je de gevraagde informatie hebt ingevuld staat |
||||
er in het bestand certificaat.crt jouw certificaat. Met dit commando kan je je nieuwe certificaat bewonderen:</p> |
||||
|
||||
<code class="terminal">openssl x509 -text -in certificaat.crt</code> |
||||
|
||||
<div class="question"> |
||||
<span class="question-string">Maak een certificaat met je eigen gegevens</span> |
||||
</div> |
||||
|
||||
<p>Een certificaat heeft ook altijd een |
||||
<em>verstrekker</em> (issuer). Dit is de persoon of bedrijf die het certificaat heeft gemaakt en daarmee garant staat dat de |
||||
identiteit die op het certificaat staat ook klopt. In jouw certificaat staat dat je over jezelf hebt gezegd dat je bent |
||||
wie je zegt dat je bent. Niet echt betrouwbare informatie dus... Iedereen zou precies datzelfde certificaat kunnen maken.</p> |
||||
|
||||
<p>Het wordt pas interessant en betrouwbaar als andere partijen het certificaat verstrekken en zo kunnen zeggen dat ze de gegevens |
||||
van het certificaat gecontroleerd hebben. Als jij die verstrekker vertrouwt dat hij zijn werk goed doet met de correctheid |
||||
van certificaten controleren. Dan vertrouw je ook indirect de gegevens op het certificaat. Zo hoef je maar een handjevol |
||||
verstrekkers te vertrouwen om bijna alle websites op het internet te kunnen vertrouwen.</p> |
||||
|
||||
<p>Elke besturingssysteem heeft een lijst van basis verstrekkers die ze impliciet vertrouwen, deze lijst kan je bekijken en |
||||
veranderen door in je geavanceerde browserinstellingen op zoek te gaan naar een knop 'Beheer certificaten' (te vinden in |
||||
het Advanced -> Certificates tabblad in Firefox).</p> |
||||
|
||||
<p> |
||||
|
||||
<div class="question"> |
||||
<span class="question-string">Hoeveel basis verstrekkers vertrouwt jouw systeem?</span> |
||||
</div> |
||||
|
||||
<div class="question"> |
||||
<span class="question-string">Bekijk het certificaat van |
||||
<a href="https://facebook.com/" target="_blank">Facebook</a>, welk bedrijf heeft dit certificaat verstrekt?</span> |
||||
</div> |
||||
|
||||
<p class="hint">Hint: Het certificaat kan je in de meeste browsers bekijken door op het slot-ikoontje te klikken. In Chrome moet je de |
||||
Developer Tools openen en kijken in het mapje 'Security'.</p> |
||||
|
||||
<h2>Mag ik uw handtekening?</h2> |
||||
|
||||
<p>Zo'n certificaat wat je aan jezelf hebt verstrekt vertrouwd natuurlijk niemand. We moeten eerst iemand vinden die jouw |
||||
certificaat wil ondertekenen.</p> |
||||
|
||||
<p>Er is een speciaal bestandsformaat om aan een verstrekker te vragen of hij jouw certificaat wil ondertekenen: |
||||
<b>.csr</b>. Dat staat voor Certificate Signing Request. Een soort van bedelbrief die je rond kan sturen met je certificaat |
||||
waar nog een verstrekker bij moet.</p> |
||||
|
||||
<p>Je kan onderstaand commando gebruiken om je eigen gemaakte certificaat als basis te gebruiken voor zo'n Certificate Signing |
||||
Request: |
||||
</p> |
||||
|
||||
<code class="terminal">openssl x509 -x509toreq -in certificaat.crt -signkey sleutel.key -out certificaat_verzoek.csr</code> |
||||
|
||||
<p>Zo'n verzoekje kan je vervolgens bij een certificaat autoriteit zoals Thawte of VeriSign inleveren. Voor een paar honderd |
||||
euro zijn ze dan bereid om hun handtekening eronder te zetten.</p> |
||||
|
||||
<p>Om deze cursus relatief goedkoop te houden heeft deze site ook een certificaat autoriteit waar je certificaten kan laten |
||||
ondertekenen: |
||||
<a href="/sign" target="signen">Certificaat Autoriteit</a>. Gebruik deze site om jouw certificaat te laten ondertekenen</p> |
||||
|
||||
<div class="question"> |
||||
<span class="question-string">Bekijk het certificaat wat je hebt teruggekregen. Welke persoon heeft dit certificaat aan jou verstrekt?</span> |
||||
</div> |
||||
|
||||
<h2>Zelf verstrekken</h2> |
||||
|
||||
<blockquote>Sometimes, the only one you can trust is yourself.</blockquote> |
||||
|
||||
<p>Om zelf verstrekker te spelen heb je helemaal geen speciale certificaten nodig. Je kan namelijk gewoon je eigen certificaat |
||||
en sleutel gebruiken die je aan het begin van de les hebt gemaakt.</p> |
||||
|
||||
<div class="question"> |
||||
<span class="question-string">Vraag een medecursist om een Certificate Signing Request van zijn certificaat te geven en onderteken dat met je eigen |
||||
certificaat. Zoek op internet het commando op waarmee je dat kan doen.</span> |
||||
</div> |
||||
|
||||
<p>Tip: zorg ervoor dat jouw certificaat standaard wordt geinstalleerd op alle besturingsystemen. Dan kan je goud geld verdienen |
||||
met het ondertekenen van andere certificaten ;)</p> |
||||
|
||||
<!-- |
||||
<h2>Websites beveiligen</h2> |
||||
|
||||
<p>Leuk die certificaten, maar laten we niet vergeten dat we er ook nog wat nuttigs mee kunnen doen. Namelijk onze internetverbindingen |
||||
beveiligen. Om hiermee te oefenen moet je |
||||
<a href="/static/vm.zip">deze virtual machine</a> downloaden. Het wachtwoord van deze VM is |
||||
<b> |
||||
<i>sec2</i> |
||||
</b>. We hebben een aantal dingen gewijzigd hierin:</p> |
||||
|
||||
<ul> |
||||
<li>Er is een default Apache installatie aanwezig.</li> |
||||
<li>www.security2.nl en websec.paulwagener.nl wijzen naar de geïnstalleerde Apache op localhost.</li> |
||||
<li>We hebben |
||||
<a href="/sign" target="signen">deze verstrekker</a> en het Let's Encrypt test certificaat als vertrouwd toegevoegd aan het systeem (dit kan je terugvinden |
||||
als je in je browser gaat kijken naar alle certificaten die zijn geïnstalleerd)</li> |
||||
</ul> |
||||
|
||||
<p>Controleer eerst of de site http://www.security2.nl in jouw VM te bereiken is, en via http |
||||
<b>s</b>://www.security2.nl/ nog niet te bereiken is. Je gaat de site in de volgende opgaven beveiligen met SSL, om dat |
||||
te doen moeten we eerst SSL aanzetten in Apache met de volgende commando's:</p> |
||||
|
||||
<code class="terminal">sudo a2enmod ssl<br> |
||||
sudo a2ensite default-ssl<br> |
||||
sudo service apache2 reload</code> |
||||
|
||||
<p class="hint">Hint: Commando's vul je in in het programma 'Terminal'</p> |
||||
|
||||
<p>De site is nu ook via https:// bereikbaar, maar Apache heeft een ongeldig dummy certificaat gebruikt om de site te beveiligen. |
||||
Om het werkend te krijgen moeten we eerst de volgende stappen uitvoeren:</p> |
||||
|
||||
<ol> |
||||
<li>Maak een geheel nieuwe certificaat/sleutel combo aan met het commando bovenaan de pagina. Je mag alles invullen zoals |
||||
je wil, behalve de Common Name / Server FQDN. Die moet |
||||
<code>www.security2.nl</code> zijn.</li> |
||||
<li>Laat het certificaat |
||||
<a href="/sign" target="signen">hier</a> weer ondertekenen</li> |
||||
<li>Kopieer het sleutel bestand en het ondertekende certificaat naar de VM</li> |
||||
<li>Voer het volgende commando uit: |
||||
<code class="terminal">sudo gedit /etc/apache2/sites-available/default-ssl.conf</code> om de standaard SSL configuratie aan te passen.</li> |
||||
<li>Verander in dit bestand de |
||||
<code>SSLCertificateFile</code> en |
||||
<code>SSLCertificateKeyFile</code> zodat ze naar jouw certificaat en sleutel bestand wijzen</li> |
||||
<li>Maak je wijzigingen actief door de configuratie opnieuw in te laden: |
||||
<code class="terminal">sudo service apache2 reload</code> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p>Als je alles goed hebt gedaan is de site nu met SSL beveiligd! Controleer of je de site in de VM nu kan bereiken via https://www.security2.nl/ |
||||
(Alleen Chrome werkt, certificaat is niet aan Firefox toegevoegd). Als je een groen slotje krijgt mag je de volgende |
||||
vraag beantwoorden:</p> |
||||
|
||||
<div class="question"> |
||||
<span class="question-string">Plak de inhoud van het .crt bestand dat je hebt gebruikt om de website te beveiligen met een groen slotje. (inclusief |
||||
begin en einde |
||||
<code>-----BEGIN CERTIFICATE-----</code>)</span> |
||||
{% include "points.html" with points=answers.answer_openssl_ssl_cert.points max="10" %} |
||||
<textarea class="question-input" name="answer_openssl_ssl_cert">{{ answers.answer_openssl_ssl_cert.string }}</textarea> |
||||
</div> |
||||
|
||||
<div class="question"> |
||||
<span class="question-string">Maak een screenshot van het groene slotje en de details van het certificaat en upload die naar |
||||
<a href="http://imgur.com" target="_blank">imgur</a>. Plak de URL naar die screenshot als antwoord.</span> |
||||
{% include "points.html" with points=answers.answer_openssl_screenshot.points max="10" %} |
||||
<input class="question-input" name="answer_openssl_screenshot" type="url" value="{{ answers.answer_openssl_screenshot.string }}"> |
||||
</div> |
||||
|
||||
<img src="/static/img/slotje_certificaat_vm.png" class="center-block screenshot" style="width: 60%"> |
||||
|
||||
<h2>Let's Encrypt</h2> |
||||
|
||||
<img src="/static/img/letsencrypt_logo.png" class="center-block"> |
||||
|
||||
<p> |
||||
<b> |
||||
</b> |
||||
</p> |
||||
|
||||
<p>Sinds 2015 is er |
||||
<a href="https://letsencrypt.org/">een nieuwe speler</a> op de markt die gratis certificaten verstrekt, mits je kan bewijzen dat jouw website van jouw is |
||||
natuurlijk. Dit gaat met behulp van de command-line |
||||
<code>letsencrypt</code> tool die automatisch certificaten maakt en ondertekend voor jouw website. Deze tool hebben we al voor je geinstalleerd |
||||
in de VM.</p> |
||||
|
||||
<p>We gaan nu websec.paulwagener.nl beveiligen, niet deze website die je nu aan het bekijken bent, maar weer de localhost |
||||
die in de VM draait. Maar nu gaan we hem met behulp van Let's Encrypt beveiligen.</p> |
||||
|
||||
<p> |
||||
<i>Tip:</i>Je mag voor deze opdracht ook een eigen domein dat je hebt beveiligen! Let even op dat de commando's dan niet |
||||
overal exact hetzelfde zijn. Zeker als je geen Apache gebruikt.</p> |
||||
|
||||
<p>Controleer eerst dat |
||||
<b>https</b>://websec.paulwagener.nl// in de VM een fout geeft, dat komt omdat het certificaat van de vorige opdracht nog |
||||
steeds van www.security2.nl is (als je de vorige opdracht goed hebt gedaan, anders krijg je misschien een andere fout). |
||||
De browser ziet dat dat niet hetzelfde domein is en geeft terecht een error.</p> |
||||
|
||||
<p>We gaan beginnen met het aanvragen van een certificaat. Dit doen we met het volgende commando: |
||||
|
||||
<code class="terminal">sudo letsencrypt certonly --manual --staging</code> |
||||
|
||||
<p>Even een korte uitleg van dit commando:</p> |
||||
|
||||
<ul> |
||||
<li> |
||||
<b>sudo</b>: letsencrypt heeft root rechten nodig, we moeten letsencrypt dus altijd met root rechten uitvoeren</li> |
||||
<li> |
||||
<b>letsencrypt</b>: de naam van het scriptje zelf. Als je dit op je eigen server wil doen moet je deze eerst installeren |
||||
(instructies vind je op de |
||||
<a href="https://letsencrypt.org/getting-started/">Let's Encrypt website</a> zelf). Afhankelijk van hoe letsencrypt is geinstalleerd kan het commando ook |
||||
<code>letsencrypt-auto</code>, |
||||
<code>certbot</code> of |
||||
<code>certbot-auto</code> zijn.</li> |
||||
<li> |
||||
<b>certonly</b>: Standaard wil Let's Encrypt volledig automatisch Apache voor je herconfigureren, maar dat gaat bij |
||||
ons niet werken omdat de VM niet |
||||
<i>echt</i> websec.paulwagener.nl is. Met de certonly optie geven we aan dat we alleen geinteresseerd zijn in het maken |
||||
van nieuwe certificaten.</li> |
||||
<li> |
||||
<b>--manual</b>: De Let's Encrypt servers geven niet zomaar certificaten weg, ze willen altijd zeker weten dat het domein |
||||
waar je een certificaat van aanvraagt ook echt van jou is. Er zijn verschillende manieren om dat te doen, maar ze |
||||
komen er allemaal op neer dat je een specifiek bestandje moet hosten op je website. Met de manual optie moeten we |
||||
onze webserver zelf goed configureren dat het bestandje te bereiken is via het domein. De andere opties ( |
||||
<code>--webroot</code>, |
||||
<code>--apache</code>) proberen het bestandje automatisch te plaatsen en de webserver te configureren. Dat gaat voor deze opdracht niet |
||||
werken omdat de echte websec.paulwagener.nl veilig ergens draait en van buiten niet te configureren is.</li> |
||||
<li> |
||||
<b>--staging</b>: Deze optie zorgt ervoor dat je een certificaat krijgt van de test server in plaats van de echte server. |
||||
Deze hebben we nodig omdat de echte server een limiet heeft van 5 certificaataanvragen per week per domein. En dat |
||||
is voor dit vak niet handig. Nadeel van de testserver is dat de certificaten een ongeldige fake verstrekker hebben |
||||
(in de VM hebben we die fake verstrekker toegevoegd als vertrouwd, zodat je alsnog een groen slotje krijgt.)</li> |
||||
</ul> |
||||
|
||||
<p>Als je dit commando voor de eerste keer uitvoert wordt er gevraagd naar je e-mailadres, daar kan je invullen wat je wil. |
||||
Voor het domein gaan we websec.paulwagener.nl invullen. Als je je eigen domein wil beveiligen vul je hier uiteraard |
||||
je eigen domein in.</p> |
||||
|
||||
<img src="/static/img/letsencrypt_domain.png" class="center-block screenshot" style="width: 80%"> |
||||
|
||||
<p>Let's Encrypt vraagt daarna om een bestandje op de server te zetten in een hele specifieke map (.well-known/acme-challenge) |
||||
op de echte websec.paulwagener.nl server. Normaliter zou dit een probleem zijn, want dat kan alleen als je toegang |
||||
hebt tot de server. Maar speciaal voor jullie is er |
||||
<a href="/letsencrypt">een pagina</a> waar je de code kan kopieren en er voor zorgen dat het bestandje 10 minuten lang op onze server wordt |
||||
gehost! |
||||
</p> |
||||
|
||||
<img src="/static/img/letsencrypt_challenge.png" class="center-block screenshot" style="width: 80%"> |
||||
|
||||
<p>Nadat de challenge is geslaagd zal Let's Encrypt nog een melding geven over dat de self-verification failed (in de VM |
||||
wijst websec.paulwagener.nl immers naar de localhost, en niet naar het bestandje op de echte server). Maar dat kan |
||||
je negeren, als het goed is gegaan staan de certificaten nu in de map |
||||
<code>/etc/letsencrypt/live/websec.paulwagener.nl</code>!. |
||||
|
||||
<img src="/static/img/letsencrypt_congrats.png" class="center-block screenshot" style="width: 80%"> |
||||
|
||||
<p>Met dit commando kan je je nieuwe certificaat bekijken:</p> |
||||
|
||||
<code class="terminal">sudo gedit /etc/letsencrypt/live/websec.paulwagener.nl/fullchain.pem</code> |
||||
|
||||
<div class="question"> |
||||
<span class="question-string">Plak de inhoud van het |
||||
<code>fullchain.pem</code> certificaat voor websec.paulwagener.nl. (inclusief alle begin en einde |
||||
<code>-----BEGIN CERTIFICATE-----</code>)</span> |
||||
{% include "points.html" with points=answers.answer_openssl_letsencrypt_fullchain.points max="0" %} |
||||
<textarea class="question-input" name="answer_openssl_letsencrypt_fullchain">{{ answers.answer_openssl_letsencrypt_fullchain.string }}</textarea> |
||||
</div> |
||||
|
||||
<p>Stel het default-ssl.conf configuratie bestand van Apache nu zo in dat het de certificaten van Let's Encrypt gebruikt:</p> |
||||
|
||||
<img src="/static/img/letsencrypt_conf.png" class="center-block screenshot"> |
||||
|
||||
<p>Sla het bestand op, reload Apache en als het goed is heb je nu een beveiligde https://websec.paulwagener.nl/, helemaal |
||||
gratis en voor niets!</p> |
||||
|
||||
<img src="/static/img/letsencrypt_chrome.png" class="center-block screenshot" style="width: 90%"> |
||||
|
||||
<p>Het zal je misschien opvallen dat de verstrekker Fake is, dat komt omdat we de |
||||
<code>--staging</code> optie hebben gebruikt. In de VM is deze toegevoegd als iets dat we kunnen vertrouwen (en dus een groen slotje oplevert), |
||||
maar in de echte wereld is dat niet zo. Zorg er dus bij je eigen website zo dat je niet de --staging optie gebruikt |
||||
als je voor de echie certificaten aan het maken bent</p> |
||||
|
||||
|
||||
|
||||
<div class="question"> |
||||
<span class="question-string">Maak een screenshot van het groene slotje en de details van het certificaat (zoals hierboven, maar natuurlijk niet |
||||
letterlijk dat plaatje, dat hebben we door) en upload die naar |
||||
<a href="http://imgur.com" target="_blank">imgur</a>. Plak de URL naar die screenshot als antwoord.</span> |
||||
{% include "points.html" with points=answers.answer_openssl_letsencrypt_screenshot.points max="0" %} |
||||
<input class="question-input" name="answer_openssl_letsencrypt_screenshot" type="url" value="{{ answers.answer_openssl_letsencrypt_screenshot.string }}"> |
||||
</div> |
||||
--> |
||||
{% endblock %} |
@ -0,0 +1,202 @@ |
||||
from django.shortcuts import render |
||||
from django.http import HttpResponse |
||||
from django.http import HttpResponseNotFound |
||||
from django.db import connection |
||||
from quiz.models import LetsEncryptChallenge |
||||
from oauth2_provider.views.generic import ProtectedResourceView |
||||
import datetime |
||||
import pytz |
||||
|
||||
|
||||
def home(request, url): |
||||
if url == 'sql' or url == '': |
||||
template = 'sql.html' |
||||
elif url == 'xss': |
||||
template = 'xss.html' |
||||
elif url == 'path': |
||||
template = 'path.html' |
||||
elif url == 'wachtwoorden': |
||||
template = 'wachtwoorden.html' |
||||
elif url == 'certificaten': |
||||
template = 'certificaten.html' |
||||
elif url == 'encryptie': |
||||
template = 'encryptie.html' |
||||
elif url == 'bonus': |
||||
template = 'bonus.html' |
||||
elif url == 'oauth': |
||||
template = 'oauth.html' |
||||
elif url == 'vm': |
||||
template = 'vm.html' |
||||
else: |
||||
return HttpResponseNotFound('404') |
||||
|
||||
# Temp |
||||
if 'vm' in request.GET: |
||||
template = 'vm.html' |
||||
|
||||
return render(request, template) |
||||
|
||||
|
||||
class SecurityApi(ProtectedResourceView): |
||||
def get(self, request, *args, **kwargs): |
||||
return HttpResponse("Geheime code: abguvatgbfrrurerzbirnybat") |
||||
|
||||
|
||||
def letsencrypt(request): |
||||
template_vars = {} |
||||
if request.method == 'POST': |
||||
try: |
||||
challengeresponse = request.POST['challenge-response'] |
||||
|
||||
if challengeresponse.strip() == '': |
||||
raise Exception('Geen data opgegeven') |
||||
|
||||
if '.' not in challengeresponse: |
||||
raise Exception( |
||||
'Verkeerde code opgegeven. De code die je moet opgeven is met een puntje er in.') |
||||
print(challengeresponse.split('.')) |
||||
if len(challengeresponse.split('.')) != 2: |
||||
raise Exception('De code moet maar 1 puntje bevatten') |
||||
|
||||
challenge, response = challengeresponse.split('.') |
||||
|
||||
if len(challenge) < 40 or len(response) < 40: |
||||
raise Exception('De code is te kort') |
||||
|
||||
expiry_date = pytz.utc.localize( |
||||
datetime.datetime.utcnow() + datetime.timedelta(minutes=10)) |
||||
challengeresponse, created = LetsEncryptChallenge.objects.get_or_create(challenge=challenge, defaults={ |
||||
'response': response, |
||||
'expiry_date': expiry_date |
||||
}) |
||||
|
||||
challengeresponse.response = response |
||||
challengeresponse.expiry_date = expiry_date |
||||
challengeresponse.save() |
||||
|
||||
template_vars['challenge'] = challenge |
||||
template_vars['response'] = response |
||||
except str as e: |
||||
template_vars['error'] = e.message |
||||
raise e |
||||
|
||||
return render(request, 'letsencrypt.html', template_vars) |
||||
|
||||
|
||||
def letsencrypt_challenge(request, challenge): |
||||
try: |
||||
# Delete old challenges |
||||
LetsEncryptChallenge.objects.filter( |
||||
expiry_date__lte=datetime.datetime.utcnow()).delete() |
||||
|
||||
challengeresponse = LetsEncryptChallenge.objects.get( |
||||
challenge=challenge) |
||||
|
||||
response = HttpResponse( |
||||
challengeresponse.challenge + "." + challengeresponse.response) |
||||
response['Content-Type'] = 'text/plain' |
||||
return response |
||||
except LetsEncryptChallenge.DoesNotExist: |
||||
return HttpResponseNotFound('404') |
||||
|
||||
|
||||
def sign(request): |
||||
if request.method == 'POST': |
||||
from OpenSSL import crypto |
||||
|
||||
ca_cert_file = """-----BEGIN CERTIFICATE----- |
||||
MIIEjzCCA3egAwIBAgIJAIyZIB4fbN2mMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD |
||||
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEBxMLTG9zIEFuZ2Vs |
||||
ZXMxDzANBgNVBAoTBlNwYWNlWDEMMAoGA1UECxMDQ0VPMRIwEAYDVQQDEwlFbG9u |
||||
IE11c2sxHjAcBgkqhkiG9w0BCQEWD2Vsb25Ac3BhY2V4LmNvbTAeFw0xNTA1Mjgx |
||||
NjEyMjFaFw0yNTA1MjUxNjEyMjFaMIGLMQswCQYDVQQGEwJVUzETMBEGA1UECBMK |
||||
Q2FsaWZvcm5pYTEUMBIGA1UEBxMLTG9zIEFuZ2VsZXMxDzANBgNVBAoTBlNwYWNl |
||||
WDEMMAoGA1UECxMDQ0VPMRIwEAYDVQQDEwlFbG9uIE11c2sxHjAcBgkqhkiG9w0B |
||||
CQEWD2Vsb25Ac3BhY2V4LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC |
||||
ggEBAMWr64mMZDfWUuYmROz+FszmwjGZvFz0CGxiExHEAFfzZfF60Rts2Qm+o7cc |
||||
bZ/UtAaIgIve5WiWhQ5mqDoyECfuVOTcddWCrskLgLafoP6nPVdTDIXsPtsjtRuV |
||||
D1ptsduDVCeQkcKFUcfLd6QXJaOAYU20gb7FJ8KFUmJXn4HXg6BsZvu8grJgh51O |
||||
29JRw83I0FxzBZw4JSvETW968NexO+aliR/inK4GQQqk4joxuT6MSVsd+17ss6wn |
||||
WO1nUNxhSW3MQePrfphkQbNZn/l1T1MfN6XAs4P9boqgENHZ2WskGIeZ5g1I4MVE |
||||
WPFTZ8HwprCvybM8mneqVp/P+FcCAwEAAaOB8zCB8DAdBgNVHQ4EFgQUHvGJ8tZM |
||||
owfGFNeyuhsYq8JN/o8wgcAGA1UdIwSBuDCBtYAUHvGJ8tZMowfGFNeyuhsYq8JN |
||||
/o+hgZGkgY4wgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQw |
||||
EgYDVQQHEwtMb3MgQW5nZWxlczEPMA0GA1UEChMGU3BhY2VYMQwwCgYDVQQLEwND |
||||
RU8xEjAQBgNVBAMTCUVsb24gTXVzazEeMBwGCSqGSIb3DQEJARYPZWxvbkBzcGFj |
||||
ZXguY29tggkAjJkgHh9s3aYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC |
||||
AQEAfe9TXLrrwA/3xf85HB+i7CxaFNTmWZvsN2Ico9Ks1/Dt7eAB61ghHFIxCqHz |
||||
LQGa77wFAI5kgzv3TembXV1kHz4pGigPC6EkNEh0Kc2O3fwz6CryK7/OrjkElKEn |
||||
ti/9loLr8+rhQKF0c2NS3qiAoYsR/kkdBZ+niT+yXCIekpQNybfDT8WqDm4Rv2s+ |
||||
u/6pZa7zZLLlORpxnuFfjjo+n/06b4+xHn+xvyGWijMcOqZdyhU0UjZ7OAW/ZEQp |
||||
3uvp8fso+Esov+Abl0Lxtr/Gk7utH/h0AD6vWJJwDlS65uqKBeuIOUoCAHy3oPH5 |
||||
p+BxtuhS2Lv5g2jHRgIxVt22rg== |
||||
-----END CERTIFICATE----- |
||||
""" |
||||
ca_key_file = """-----BEGIN RSA PRIVATE KEY----- |
||||
MIIEogIBAAKCAQEAxavriYxkN9ZS5iZE7P4WzObCMZm8XPQIbGITEcQAV/Nl8XrR |
||||
G2zZCb6jtxxtn9S0BoiAi97laJaFDmaoOjIQJ+5U5Nx11YKuyQuAtp+g/qc9V1MM |
||||
hew+2yO1G5UPWm2x24NUJ5CRwoVRx8t3pBclo4BhTbSBvsUnwoVSYlefgdeDoGxm |
||||
+7yCsmCHnU7b0lHDzcjQXHMFnDglK8RNb3rw17E75qWJH+KcrgZBCqTiOjG5PoxJ |
||||
Wx37XuyzrCdY7WdQ3GFJbcxB4+t+mGRBs1mf+XVPUx83pcCzg/1uiqAQ0dnZayQY |
||||
h5nmDUjgxURY8VNnwfCmsK/Jszyad6pWn8/4VwIDAQABAoIBAHkzyOA17N0v1PS5 |
||||
UlneEizg8QFouk5kcyXBnN+vxmYnH8LJA55FR27qLYgBLlZqHVhEKk2ZBiDy6fLC |
||||
jzPfrnhNclBBvR6FWpZ7LxjLF/QMp1f73BnhmUjUxB99bkSMLhnilJ8NzdHv3Q0c |
||||
fOdoKfPuq7rxivxl9tMW3ETgZTU+0dSeJH8ZkkcQblckNpqP//oWFpXYrgftgyR3 |
||||
kM+uZya2kwaZ15XC2O1IXbvFVjppw4z/z8KMBc6azGrSFJ6xGkve+1KKBuVQ1Vpg |
||||
sFXBaKHoVG5NpGiwiBkbERkn1Jp+lgJkstDyzGtIVmhzT7g5+YIvXE5uWU/NVRDp |
||||
0n8n6UECgYEA/hgkUfJ/uVlORhkIyW+thG9VPO1k35BdOjw5f7xDN6DSyYNSRubi |
||||
q6F3KWW807fEubGYzXaTh5QCB9z+gUuVAtjo9Mb0RPBEyWwXFi0ynxLzNQxA692U |
||||
Id67JHVPK4gsgP7jZi8+pAbN3xSfRG1BXdsp+RUJdWNiaLeWOsHI+bMCgYEAxydy |
||||
enmg+dzz8qz6my9G9uH0dqoG8BHlwPp7h/vmSbhWAD4+BIGCHbGt2zk/Zh7w6PsQ |
||||
9nMrWSwAkStdpW0WLz/oNIijVN8dInlFnB3qq6o1t0Jrz2K4ngUN1PAA19Ft1s+r |
||||
VZpSM+uKViKKuthORNeVM0D3D3gfrisdAZAV7M0CgYBguef5mgqtECYP4S/LHsw7 |
||||
Afa8vtILmPUkWhC5Y31jC8GyHF+Rxgq7szeddrEvF2G4HrdAX8dBcUJko+fuaEtN |
||||
Ti1AIQyTwbMtygvv0TzX+WrD4upD35GoYxVyh4Wf2LK4WE9QcuOxpTVxmnQWpFCh |
||||
3fBYdX2oRjEME/cIXwSWqQKBgEpc0WMn/VKvDSvlKSI+8fmHf3e7nyGPHUIEhZHO |
||||
HjwSp5Ipq5CVJxedW7SK2MBx9zSXYssTT/FY+9E45xu48tqruzG6f3pWYROZQsO7 |
||||
a/+za6FFHOpwC019x59mCnqLib73BhvNproaTipBdZm04OzVrrFXpajSCspG8Oq/ |
||||
eWBVAoGACI+4ROdYWCprQRgH2Qr5nKnRkN1mZzBl4hgodSGCZa3TWnBVHtXacluF |
||||
KJ8dp3ZgjiQ9aQujFD5oPnmSJ8wvJijF8ngEFw60+axRrWnUmejWkrexA1Hlv0Er |
||||
tq9DcELddZK2gJXaXpL1wOL+Ex5RzzRmjqKmmkkn1//ikn+nrZU= |
||||
-----END RSA PRIVATE KEY----- |
||||
""" |
||||
csr = crypto.load_certificate_request( |
||||
crypto.FILETYPE_PEM, request.FILES['csr'].read()) |
||||
ca_cert = crypto.load_certificate(crypto.FILETYPE_PEM, ca_cert_file) |
||||
ca_key = crypto.load_privatekey(crypto.FILETYPE_PEM, ca_key_file) |
||||
|
||||
signed_cert = crypto.X509() |
||||
signed_cert.set_serial_number(1) |
||||
signed_cert.gmtime_adj_notBefore(0) |
||||
signed_cert.gmtime_adj_notAfter(60 * 60 * 24 * 365 * 5) |
||||
signed_cert.set_issuer(ca_cert.get_subject()) |
||||
signed_cert.set_subject(csr.get_subject()) |
||||
signed_cert.set_pubkey(csr.get_pubkey()) |
||||
signed_cert.sign(ca_key, 'sha256') |
||||
|
||||
response = HttpResponse(crypto.dump_certificate( |
||||
crypto.FILETYPE_PEM, signed_cert), content_type='application/zip') |
||||
response['Content-Disposition'] = 'attachment; filename=signed-certificaat.crt' |
||||
return response |
||||
|
||||
return render(request, 'sign.html') |
||||
|
||||
|
||||
def graderhelper(request): |
||||
cursor = connection.cursor() |
||||
if request.GET['mode'] == 'oauth_app': |
||||
cursor.execute("SELECT COUNT(id) FROM oauth2_provider_application WHERE client_id = %s", [ |
||||
request.GET['answer']]) |
||||
return HttpResponse(cursor.fetchone()) |
||||
|
||||
elif request.GET['mode'] == 'access_token': |
||||
cursor.execute("SELECT COUNT(id) FROM oauth2_provider_accesstoken WHERE token = %s", [ |
||||
request.GET['answer']]) |
||||
return HttpResponse(cursor.fetchone()) |
||||
|
||||
elif request.GET['mode'] == 'auth_code': |
||||
cursor.execute("SELECT COUNT(id) FROM oauth2_provider_grant WHERE code = %s", [ |
||||
request.GET['answer']]) |
||||
return HttpResponse(cursor.fetchone()) |
||||
|
||||
return HttpResponse('404') |
@ -0,0 +1,12 @@ |
||||
import os |
||||
import sys |
||||
from django.core.wsgi import get_wsgi_application |
||||
|
||||
path = os.path.dirname(os.path.abspath(__file__)) |
||||
if path not in sys.path: |
||||
sys.path.append(path) |
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "securityquiz.settings") |
||||
|
||||
|
||||
application = get_wsgi_application() |
Loading…
Reference in new issue