Merge branch 'master' of github.com:Avans/Security-Quiz

Paul Wagener 8 years ago
commit 7f1923943f
  1. 26
      quiz/migrations/0004_letsencryptchallenge.py
  2. 5
      quiz/models.py
  3. 3
      quiz/tests.py
  4. 3
      quiz/views.py
  5. 28
      securityquiz/settings.py
  6. 25
      securityquiz/urls.py
  7. 11
      static/css/semantic.min.css
  8. BIN
      static/img/bleep.png
  9. BIN
      static/img/letsencrypt_challenge.png
  10. BIN
      static/img/letsencrypt_chrome.png
  11. BIN
      static/img/letsencrypt_conf.png
  12. BIN
      static/img/letsencrypt_congrats.png
  13. BIN
      static/img/letsencrypt_domain.png
  14. BIN
      static/img/letsencrypt_logo.png
  15. BIN
      static/img/loader.gif
  16. BIN
      static/img/whatsapp.png
  17. BIN
      static/img/whatsapp_qr.png
  18. 7
      static/js/quiz.js
  19. 17
      static/js/semantic.min.js
  20. 4
      templates/base.html
  21. 92
      templates/certificaten.html
  22. 43
      templates/encryptie.html
  23. 53
      templates/letsencrypt.html
  24. 18
      templates/oauth.html
  25. 8
      templates/sql.html
  26. 2
      templates/xss.html
  27. 73
      views.py

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('quiz', '0003_auto_20150520_1113'),
]
operations = [
migrations.CreateModel(
name='LetsEncryptChallenge',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('challenge', models.CharField(max_length=128)),
('response', models.CharField(max_length=128)),
('expiry_date', models.DateTimeField()),
],
options={
},
bases=(models.Model,),
),
]

@ -18,3 +18,8 @@ class Answer(models.Model):
def __str__(self):
return self.question + ": " + self.string
class LetsEncryptChallenge(models.Model):
challenge = models.CharField(max_length=128)
response = models.CharField(max_length=128)
expiry_date = models.DateTimeField()

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

@ -1,3 +0,0 @@
from django.shortcuts import render
# Create your views here.

@ -23,11 +23,8 @@ SECRET_KEY = secrets.SECRET_KEY
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
TEMPLATE_DEBUG = False
if 'runserver' in sys.argv:
DEBUG = True
TEMPLATE_DEBUG = True
ALLOWED_HOSTS = ['sec1.aii.avans.nl']
@ -98,10 +95,22 @@ STATIC_URL = '/static/'
PROJECT_PATH = os.path.realpath(os.path.dirname(__file__)) + '/..'
MEDIA_ROOT = PROJECT_PATH + '/media/'
# Additional locations of static files
TEMPLATE_DIRS = (
PROJECT_PATH + '/templates',
)
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',
@ -109,8 +118,3 @@ STATICFILES_DIRS = (
def closed(request):
return {'CLOSED': CLOSED}
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'securityquiz.settings.closed'
)

@ -1,18 +1,21 @@
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
import views
from views import SecurityApi
admin.autodiscover()
urlpatterns = patterns('',
urlpatterns = [
# Examples:
url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
url(r'^api/hello', SecurityApi.as_view()),
url(r'^callback$', 'views.avans_callback'),
url(r'^logout$', 'views.avans_logout'),
url(r'^pull$', 'views.git_pull'),
url(r'^api/hello', views.SecurityApi.as_view()),
url(r'^callback$', views.avans_callback),
url(r'^logout$', views.avans_logout),
url(r'^pull$', views.git_pull),
url(r'^admin/', include(admin.site.urls)),
url(r'^save$', 'views.save'),
url(r'^sign$', 'views.sign'),
url(r'^(.*)$', 'views.home', name='home'),
)
url(r'^save$', views.save),
url(r'^sign$', views.sign),
url(r'^graderhelper$', views.graderhelper),
url(r'^letsencrypt$', views.letsencrypt),
url(r'^\.well-known/acme-challenge/(.+)', views.letsencrypt_challenge),
url(r'^(.*)$', views.home, name='home'),
]

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

@ -8,9 +8,14 @@ $(function() {
$('#save-button').click(function() {
var data = $.base64.encode($('#form-quiz').serialize())
console.log(data);
$('#busy').show();
$('#save-button').prop('disabled', true);
$.post('save', data, function(data) {
$('#busy').hide();
$('#save-button').prop('disabled', false);
if(data == 'ok') {
$('#js-message').text('Antwoorden zijn opgeslagen').slideDown().delay(1000).slideUp();
changed = false;

File diff suppressed because one or more lines are too long

@ -40,9 +40,9 @@
</select>
<a href="/logout" class="btn">Uitloggen</a>
{% if CLOSED %}<br>Inzendingen kunnen niet meer worden ingezonden{% else %}<button class="btn-primary btn-disabled" type="submit" id="save-button">Opslaan</button>{% endif %}
{% if CLOSED %}<br>Inzendingen kunnen niet meer worden ingezonden{% else %}<button class="btn-primary btn-disabled" type="submit" id="save-button">Opslaan</button><img src="/static/img/loader.gif" id="busy" style="display: none">{% endif %}
<div class="alert alert-info" id="js-message" style="display: none;"></div>
<p>Deadline: woensdag 17 juni 23:59</p>
<p>Deadline: donderdag 16 juni 23:59</p>
</div>
<div id="quiz" class="span8 offset3">

@ -11,7 +11,7 @@
<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.conf</code>
<code class="terminal">SET OPENSSL_CONF=[pad naar bestand]\openssl.cfg</code>
<hr>
@ -43,7 +43,7 @@
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 Security tabblad in Firefox).</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>
@ -87,14 +87,28 @@
<textarea class="question-input" name="answer_openssl_signed_cert">{{ answers.answer_openssl_signed_cert.string }}</textarea>
</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. Vraag een medestudent 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.</p>
<div class="question">
<span class="question-string">Plak de inhoud van het certificaat van een medestudent, waar je zelf verstrekker van bent. (inclusief begin en einde <code>-----BEGIN CERTIFICATE-----</code>)</span>
{% include "points.html" with points=answers.answer_openssl_sign_other.points max="10" %}
<textarea class="question-input" name="answer_openssl_sign_other">{{ answers.answer_openssl_sign_other.string }}</textarea>
</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 hebben we een Ubuntu VM klaargezet op BlackBoard. Het wachtwoord van deze VM is <b><i>sec2</i></b>. We hebben een aantal dingen gewijzigd hierin:</p>
<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 wijst naar de geïnstalleerde Apache op localhost.</li>
<li>We hebben <a href="/sign" target="signen">deze verstrekker</a> 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>
<li>www.security2.nl en sec1.aii.avans.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>
@ -120,7 +134,7 @@ sudo service apache2 reload</code>
<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="15" %}
{% 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>
@ -132,20 +146,70 @@ sudo service apache2 reload</code>
<img src="/static/img/slotje_certificaat_vm.png" class="center-block screenshot" style="width: 60%" >
<p>Tip: Heb je zelf een website die je wil beveiligen? <a href="http://startssl.com/" target="_blank">Start SSL</a> is één van de weinige bedrijven die gratis certificaten ondertekenen. Medio 2015 kan het ook via <a href="http://letsencrypt.org/" target="_blank">Let's Encrypt</a></p>
<h2>Let's Encrypt</h2>
<h2>Zelf verstrekken</h2>
<img src="/static/img/letsencrypt_logo.png" class="center-block">
<blockquote>Sometimes, the only one you can trust is yourself.</blockquote>
<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>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. Vraag een medestudent 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.</p>
<p>We gaan nu sec1.aii.avans.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>://sec1.aii.avans.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> sec1.aii.avans.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 sec1.aii.avans.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 sec1.aii.avans.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 sec1.aii.avans.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 sec1.aii.avans.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/sec1.aii.avans.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/sec1.aii.avans.nl/fullchain.pem</code>
<div class="question">
<span class="question-string">Plak de inhoud van het certificaat van een medestudent, waar je zelf verstrekker van bent. (inclusief begin en einde <code>-----BEGIN CERTIFICATE-----</code>)</span>
{% include "points.html" with points=answers.answer_openssl_sign_other.points max="10" %}
<textarea class="question-input" name="answer_openssl_sign_other">{{ answers.answer_openssl_sign_other.string }}</textarea>
<span class="question-string">Plak de inhoud van het <code>fullchain.pem</code> certificaat voor sec1.aii.avans.nl. (inclusief alle begin en einde <code>-----BEGIN CERTIFICATE-----</code>)</span>
{% include "points.html" with points=answers.answer_openssl_letsencrypt_fullchain.points max="10" %}
<textarea class="question-input" name="answer_openssl_letsencrypt_fullchain">{{ answers.answer_openssl_letsencrypt_fullchain.string }}</textarea>
</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>
<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://sec1.aii.avans.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="10" %}
<input class="question-input" name="answer_openssl_letsencrypt_screenshot" type="url" value="{{ answers.answer_openssl_letsencrypt_screenshot.string }}">
</div>
{% endblock %}

@ -71,7 +71,7 @@
<img src="static/img/sleutels_genereren.png">
<p>Om een bestandje te versleutelen nemen we bijvoorbeeld de groene sleutel en encrypten het met het algoritme. Maar we kunnen het bestand nu niet meer ontsleutelen met de groene sleutel. <b>Met alleen de bijbehorende rode sleutel kan je nu het bestand ontsleutelen</b>. Andersom werkt ook, bestanden die je met de rode sleutel versleuteld, zijn enkel en alleen met de groene sleutel te ontsleutelen.</p>
<p>Om een bestandje te versleutelen nemen we bijvoorbeeld de groene sleutel en gebruiken we die om het bestandje te versleutelen. Maar we kunnen het bestand nu niet meer ontsleutelen met de groene sleutel. <b>Met alleen de bijbehorende rode sleutel kan je nu het bestand ontsleutelen</b>. Andersom werkt ook, bestanden die je met de rode sleutel versleuteld, zijn enkel en alleen met de groene sleutel te ontsleutelen.</p>
<img src="static/img/asym_encryptie.png">
@ -89,32 +89,37 @@
<div class="question">
<span class="question-string">Hoe kan Alice een bericht naar Bob versturen zodat:
<span class="question-string">Hoe kan Alice een bericht naar Bob versturen zodat de volgende dingen tegelijkertijd gelden:
<ol>
<li>Alleen Bob het bericht kan lezen</li>
<li>Bob zeker weet dat het bericht van Alice is</li>
<li>Niemand het bericht kan onderscheppen en lezen</li>
<li>Alleen Bob kan het bericht lezen</li>
<li>Bob weet zeker dat het bericht van Alice is</li>
</ol>
Leg uit in welke volgorde Alice en Bob encrypten, decrypten en versturen en met welke sleutels. Je mag er van uit gaan dat ze (alleen) elkaars publieke sleutel weten.
Leg uit in welke volgorde Alice en Bob encrypten, decrypten en versturen en met welke sleutels. Je mag er van uit gaan dat ze elkaars publieke sleutel weten en die .
</span>
{% include "points.html" with points=answers.answer_encryption_securesend.points max="10" %}
<textarea class="question-input" name="answer_encryption_securesend">{{ answers.answer_encryption_securesend.string }}</textarea>
</div>
<img src="static/img/bleep.png">
<p class="hint"><strong>Hint:</strong> het is natuurlijk mogelijk om een versleuteld bericht nog een keer te versleutelen.</p>
<p>Deze screenshot hebben we op internet gevonden van een app die beweert dat alle chatberichten 100% geheim blijven en dat het bedrijf zelf niet de berichten kan lezen. De berichten worden wel verstuurd via de servers van Bleep. Als je een geheime chat wil beginnen moet je eerst elkaars QR code scannen.</p>
<img src="static/img/whatsapp.png" class="screenshot center-block" style="width: 70%">
<p>WhatsApp beweert dat alle berichten end-to-end versleuteld verstuurd worden. Daarmee zou niemand de berichten kunnen lezen die via hun servers verstuurd worden, zelfs zij zelf niet. Alleen de afzender en de ontvanger kunnen de berichten lezen.</p>
<p>Om dat te controleren kan je bij de contactinformatie van elke chat klikken op 'Encryptie', je krijgt dan een QR code en een lijst van cijfers. Als de cijfers allemaal hetzelfde zijn zou je zeker moeten weten dat berichtjes alleen door jou en de andere persoon gelezen kunnen worden.</p>
<img src="static/img/whatsapp_qr.png" class="screenshot center-block" style="width: 50%">
<div class="question">
<span class="question-string">Leg kort uit hoe de app deze claim kan waarmaken, waarom daar de QR code voor nodig is en hoe beveiligde berichten waarschijnlijk verstuurd worden (niet alleen maar: 'het wordt versleuteld').</span>
{% include "points.html" with points=answers.answer_encryption_bleep.points max="10" %}
<textarea class="question-input" name="answer_encryption_bleep">{{ answers.answer_encryption_bleep.string }}</textarea>
<span class="question-string">Zoek op internet welke informatie er in de QR code staat. Hoe kan WhatsApp met die informatie garanderen dat alleen jullie twee de chat kan lezen?</span>
{% include "points.html" with points=answers.answer_encryption_whatsapp.points max="10" %}
<textarea class="question-input" name="answer_encryption_whatsapp">{{ answers.answer_encryption_whatsapp.string }}</textarea>
</div>
<h2>GPG</h2>
<p>Genoeg theorie, we gaan aan de slag met concrete encryptiealgoritmes. En wel met de <a href="http://en.wikipedia.org/wiki/Pretty_Good_Privacy#OpenPGP" target="_blank">OpenPGP</a> (Pretty Good Privacy) standaard. Een veel gebruikt open source programma die deze standaard is <a href="http://en.wikipedia.org/wiki/GNU_Privacy_Guard" target="_blank">GPG</a> (GNU Privacy Guard). Met dit programma kunnen we sleutelparen maken, bestanden encrypten/decrypten en versleutelde berichten versturen.</p>
<p>Genoeg theorie, we gaan aan de slag met concrete encryptiealgoritmes. En wel met de <a href="http://en.wikipedia.org/wiki/Pretty_Good_Privacy#OpenPGP" target="_blank">OpenPGP</a> (Pretty Good Privacy) standaard. Een veel gebruikt open source programma die deze standaard implementeert is <a href="http://en.wikipedia.org/wiki/GNU_Privacy_Guard" target="_blank">GPG</a> (GNU Privacy Guard). Met dit programma kunnen we sleutelparen maken, bestanden encrypten/decrypten en versleutelde berichten versturen.</p>
<p>Om het makkelijker te maken om publieke sleutels uit te wisselen kan GPG gebruik maken van een <b>keyserver</b>. Dit is een speciale server die een lijst van publieke sleutels bijhoud. Voor onderstaande opdrachten hebben we onze eigen keyserver ingericht op sec1.aii.avans.nl. <b>Deze werkt niet als je de opdrachten thuis maakt</b>. De Avans firewall blokkeert poort 11371 waarop deze server werkt. Als je thuis de opdrachten wilt maken kan je het beste <a href="https://vmview-1.aii.avans.nl/" target="_blank">inloggen</a> op een PANO-box VM. Daar werkt het wel.</p>
@ -138,7 +143,7 @@
<li><b>-a</b> Output in ASCII base64 formaat</li>
<p>
<p>Haal van de keyserver onze publieke sleutel op met sleutel-ID <b>FA9E1C5A</b>. We hebben met onze private sleutel een tekst versleuteld in <a href="static/secret.txt.asc" target="_blank">dit bestand</a>. Gebruik de publieke sleutel om dit bestand te ontsleutelen.</p>
<p>Haal van de keyserver onze publieke sleutel op met sleutel-ID <b>FA9E1C5A</b> (GPG noemt dit ook wel de user-ID). We hebben met onze private sleutel een tekst versleuteld in <a href="static/secret.txt.asc" target="_blank">dit bestand</a>. Gebruik de publieke sleutel om dit bestand te ontsleutelen.</p>
<div class="question">
<span class="question-string">Welke zin hebben we versleuteld?</span>
@ -154,12 +159,18 @@
<textarea class="question-input" name="answer_encryption_encrypt_public_key">{{ answers.answer_encryption_encrypt_public_key.string }}</textarea>
</div>
<p class="hint"><strong>Hint:</strong> Het is met GPG mogelijk om meerdere ontvangers op te geven. Dat hoeft voor deze opdracht niet. Als je alle (1 dus) ontvangers hebt opgegeven moet je een lege regel opgeven om aan te geven dat je verder wil gaan.</p>
<p class="hint"><strong>Hint:</strong> Gebruik onze sleutel-ID (ook wel user-id) die we eerder al hebben genoemd.</p>
<p class="hint"><strong>Hint:</strong> Krijg je een binair bestand? Dan ben je waarschijnlijk vergeten om de ASCII base64 optie aan te zetten (zie lijst van opties hierboven)</p>
<p>Tijd om je eigen sleutels te gebruiken! Maak je eigen publieke/private sleutelpaar en verstuur de publieke sleutel naar de sec1.aii.avans.nl keyserver. <b>Gebruik je Avans e-mailadres voor het e-mailveld</b>.</p>
<p>Vergeet niet om je publieke sleutel naar de sec1.aii.avans.nl keyserver te sturen zodat anderen die kunnen opzoeken en geheime berichten naar je kunnen sturen (en zodat wij de opdrachten kunnen nakijken)</p>
<p>Vergeet niet om je publieke sleutel naar de sec1.aii.avans.nl keyserver te sturen zodat anderen die kunnen opzoeken en geheime berichten naar je kunnen sturen (en zodat wij de opdrachten kunnen nakijken, anders krijg je de punten voor onderstaande opdracht niet!)</p>
<div class="question">
<span class="question-string">Versleutel een bestandje met de tekst "Security 2" met je eigen private sleutel. Plak de versleutelde tekst in het tekstveld</span>
<span class="question-string">Versleutel een bestandje met de tekst "Security 2" met je eigen private sleutel. Plak de versleutelde tekst in het tekstveld (inclusief begin en einde <code>-----BEGIN PGP MESSAGE-----</code>)</span>
{% include "points.html" with points=answers.answer_encryption_encrypt_with_own_private.points max="5" %}
<textarea class="question-input" name="answer_encryption_encrypt_with_own_private">{{ answers.answer_encryption_encrypt_with_own_private.string }}</textarea>
</div>
@ -180,6 +191,8 @@
<input class="question-input" name="answer_encryption_sign_keys" value="{{ answers.answer_encryption_sign_keys.string }}">
</div>
<p class="hint"><strong>Hint:</strong> Handtekeningen worden pas verstuurd als je de sleutel die je hebt ondertekend weer terugstuurt naar de server.</p>
<p>Heb je de smaak te pakken? Dan kan je je eigen publieke sleutel ook doorsturen naar andere <a href="http://en.wikipedia.org/wiki/Key_server_%28cryptographic%29" target="_blank">keyservers</a> en laten ondertekenen bij hippe <a href="http://en.wikipedia.org/wiki/Key_signing_party" target="_blank">key signing parties</a>.</p>
<a href="http://xkcd.com/364/" target="_blank"><img src="http://imgs.xkcd.com/comics/responsible_behavior.png"></a>

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/static/css/semantic.min.css">
<style type="text/css">
body {
margin-top: 20px;
}
</style>
</head>
<body>
<h1 class="ui centered aligned header">Let's Encrypt</h1>
<div class="ui three column centered grid">
<div class="column ui">
<form method="POST" action="" class="ui form primary center aligned segment">
{% csrf_token %}
{% if challenge %}
<p>Vanaf<br>
<a href="http://sec1.aii.avans.nl/.well-known/acme-challenge/{{challenge}}">http://sec1.aii.avans.nl/.well-known/acme-challenge/{{challenge}}</a><br> wordt de komende 10 minuten de volgende tekst getoond:<br>
<code>{{challenge}}.{{response}}</code>
{% elif error %}
<div class="ui negative message">
<p>{{error}}</p>
</div>
{% else %}
<div class="field">
<label for="domain">Challenge-response</label>
<div class="ui huge input">
<textarea name="challenge-response" value="" style="text-align: center;" placeholder=""></textarea>
</div>
<p>Vul hier de code in die Let's Encrypt van je vraagt om te geven via <br><code>http://sec1.aii.avans.nl/.well-known/acme-challenge/</code></p>
</div>
<button type="submit" class="ui big blue submit button">Opslaan</button>
{% endif %}
</form>
</div>
</div>
</div>
</body>
</html>

@ -15,7 +15,7 @@
<h3>Simpele authenticatie</h3>
<p>Een simpele manier om de saldo API te implementeren is om rechtstreeks je gebruikersnaam en wachtwoord mee te geven in de API request. De server checkt of de inloggegevens correct zijn en geeft de saldo informatie terug van die gebruiker terug. Uiteraard moet dit alles over een beveiligde verbinding gebeuren, maar als dat zo is is het in theorie een veilige oplossing.</p>
<p>Een simpele manier om de saldo API te implementeren is om rechtstreeks je gebruikersnaam en wachtwoord mee te geven in de API request. De server checkt of de inloggegevens correct zijn en geeft de saldo informatie van die gebruiker terug. Uiteraard moet dit alles over een beveiligde verbinding gebeuren, maar als dat zo is is het in theorie een veilige oplossing.</p>
<figure>
<img src="static/img/auth_basic.png">
@ -129,6 +129,8 @@
<input class="question-input" name="answer_oauth_implicit_access_token" value="{{ answers.answer_oauth_implicit_access_token.string }}"></input>
</div>
<p class="hint"><strong>Hint:</strong> Let je wel op dat er een slash staat achter <code>authorize</code> in de URL?</p>
<div class="question">
<span class="question-string">Hoeveel seconden is deze token code geldig?</span>
{% include "points.html" with points=answers.answer_oauth_implicit_access_token_expires.points max="5" %}
@ -149,6 +151,8 @@
<input class="question-input" name="answer_oauth_api_hello" value="{{ answers.answer_oauth_api_hello.string }}"></input>
</div>
<p class="hint"><strong>Hint:</strong> Let op dat je de Authorization data als <i>header</i> meestuurt. Via de POST form-data of als URL parameter gaat niet werken!</p>
<h3>Web applicaties</h3>
@ -185,7 +189,7 @@
<li><b>client_secret</b>: De client secret die je hebt verzonnen</li>
</ul>
<p>Doe er niet te lang over, authorisatie codes verlopen vaak al na enkele minuten. Als je het goed doet krijg je een response met daarin de refresh_token (en een gratis access_token!). Als je een <code>invalid_grant</code> error krijgt betekent dat dat jouw code verlopen is en dat je een nieuwe moet aanvragen. Als je een <code>invalid_client</code> error krijgt moet je goed controleren of je redirect_uri, client_id en client_secret allemaal goed staan ingesteld.</p>
<p>Doe er niet te lang over, authorisatie codes verlopen vaak al na enkele minuten. Als je het goed doet krijg je een response met daarin de refresh_token (en een gratis access_token!). Als je een <code>invalid_grant</code> error krijgt betekent dat dat jouw code verlopen is en dat je een nieuwe moet aanvragen. Als je een <code>invalid_client</code> error krijgt moet je goed controleren of je redirect_uri, client_id en client_secret allemaal goed staan ingesteld. En als je een <code>access_denied</code> krijgt moet je nog een keer heel goed controleren of je redirect_uri echt <i>exact</i> hetzelfde is als toen je je app hebt geregistreerd.</code>. Krijg je een andere error? Controleer dan nog een keer extra goed of de URL eindigt op <code>/token/</code> (die laatste slash is belangrijk!) en dat je alle data verstuurd als form data via POST.</p>
<img src="static/img/oauth_exchange_auth_code.png" class="screenshot" style="margin: 20px; width: 80%; margin-left: auto; margin-right: auto;">
@ -207,10 +211,12 @@
<code style="display: block;">
Client id: 799427728270-ahr6bg713mtkh2htskbmqko8hpheq1md.apps.googleusercontent.com<br>
Client secret: 3W9FcQefBmhX7CT1FgzqiCdR<br>
Refresh token: 1/HJDF6uiwgUKdfSTsZxdeDu-9iSpgIa2D3ShoIwr5hE0<br></code>
Refresh token: 1/WfdEEjWgj5Lm8p6wZzoTCeirQz7e4hMDIxvOkdvSjsU<br></code>
<p>Met deze gegevens kunnen we weer een POST doen naar de token endpoint (voor Google: https://accounts.google.com/o/oauth2/token) om een access token te genereren. Dit keer hoeven we geen redirect_uri mee te sturen en moeten we de grant_type parameter op 'refresh_token' zetten:</p>
<p class="hint"><strong>Hint:</strong> Deze keer geen slash achteraan de token URL endpoint, goed opletten!</p>
<img src="static/img/oauth_google_refresh.png" class="screenshot" style="width: 70%; margin: 20px; display: block">
<p>Gebruik de access token die je krijgt om een API call te doen naar <span class="url">https://www.googleapis.com/calendar/v3/calendars/secavans@gmail.com/events</span>. Vergeet niet weer de juiste Authorization header te gebruiken om je access token in te zetten! Als je het goed doet krijg je alle events uit onze Google Calender te zien in JSON formaat.</p>
@ -229,16 +235,18 @@
<p>Gebruik de authorisatie URL zoals die <a href="https://developers.google.com/identity/protocols/OAuth2WebServer#formingtheurl" target="_blank">hier</a> staat gedocumenteerd.</p>
<p class="hint"><strong>Hint: </strong>Vergeet niet de juiste scope te gebruiken zodat de gebruiker ook echt toestemming kan geven voor een bepaalde API. Bij Google zijn de scopes meestal URL's. Voor Google Calendar kan je de scope bijvoorbeeld <a href="https://developers.google.com/google-apps/calendar/auth">hier</a> vinden</p>
<div class="question">
<span class="question-string">Beschrijf de HTTP requests die je hebt gemaakt om de token te krijgen en de API te gebruiken (en ook de uitkomst van die requests). Gevoelige data mag je met ***** censureren.</span>
<span class="question-string">Beschrijf de HTTP requests die je hebt gemaakt om de token te krijgen EN de API te gebruiken (en ook de uitkomst van die requests). Gevoelige data mag je met ***** censureren.</span>
{% include "points.html" with points=answers.answer_oauth_google_requests.points max="15" %}
<textarea class="question-input" name="answer_oauth_google_requests" style="height: 200px">{{ answers.answer_oauth_google_requests.string }}</textarea>
</div>
<h3>Mini webapp</h3>
<p>Maak een kleine webapplicatie in PHP waarmee je de requests uit de vorige opdracht automatisch uitvoert (je mag ook een OAuth framework gebruiken)</p>
<p>Maak een kleine webapplicatie in PHP of JavaScript waarmee je de requests uit de vorige opdracht automatisch uitvoert (je mag ook een OAuth framework gebruiken)</p>
<img src="static/img/webapp1.png" class="screenshot" style="width: 40%">
<img src="static/img/webapp2.png" class="screenshot" style="width: 40%">

@ -56,7 +56,7 @@
<code>SELECT naam FROM leden WHERE id=<i>0; DROP TABLE leden;</i></code>
<p>Met <code>;</code> geven we aan dat we een nieuwe query beginnen, waarna we vervolgens vrij zijn om elke query uit te voeren die we maar willen. Let wel dat het uitvoeren van meerdere queries met bijvoorbeeld mysqli_query() is iets wat standaard uit staat. Deze techniek is extra gevaarlijk omdat deze immuun is tegen escapen als het invoer is die niet tussen quotejes staat.</p>
<p>Met <code>;</code> geven we aan dat we een nieuwe query beginnen, waarna we vervolgens vrij zijn om elke query uit te voeren die we maar willen. Let wel dat het uitvoeren van meerdere queries met bijvoorbeeld mysqli_query() iets is wat standaard uit staat. Deze techniek is extra gevaarlijk omdat deze immuun is tegen escapen als het invoer is die niet tussen quotejes staat.</p>
<h5>UNION</h5>
@ -69,13 +69,13 @@
<img src="/static/img/shield.png" style="float: right">
<h4>Countermeasures</h4>
<p>Het is niet moeilijk om bovenstaande aanvallen te voorkomen, met een paar simpele aanpassingen kan je ervoor zorgen dat je SQL altijd wordt uitgevoerd zoals je die bedoeld hebt.</p>
<p>Het is niet moeilijk om bovenstaande aanvallen te voorkomen. Met een paar simpele aanpassingen kan je ervoor zorgen dat je SQL altijd wordt uitgevoerd zoals je die bedoeld hebt.</p>
<h5>Stored procedures</h5>
<p>Je slaat de SQL op als stored procedure in de database en roept deze aan vanuit je code. Omdat de SQL in de database staat in plaats op de server is SQL injectie niet mogelijk</p>
<h5>Prepared statements</h5>
<p>De meest gebruikte veilige manier, met vraagtekentjes geef je aan op welke plekken de invoer moet komen en vul die later in. De SQL wordt altijd uitgevoerd zoals je hem hebt bedoeld, en ook hier is SQL injectie onmogelijk. Lees <a href="http://php.net/manual/en/mysqli.prepare.php" target="_blank">hier</a> verder</p>
<p>Dit is de meest gebruikte en veilige manier. Met vraagtekentjes geef je aan op welke plekken de invoer moet komen en die vul je dan later in. De SQL wordt altijd uitgevoerd zoals je hem bedoeld hebt. En ook hier is SQL injectie onmogelijk. Lees <a href="http://php.net/manual/en/mysqli.prepare.php" target="_blank">hier</a> verder</p>
<h5>Escaping</h5>
<p>Je kan ook alle invoer zelf escapen met functies zoals <a href="http://php.net/manual/en/mysqli.real-escape-string.php" target="_blank">mysqli_real_escape_string()</a>. Zorg ervoor dat je dan consequent alle strings escaped met die functie en alle getallen cast naar int's voordat je ze in je SQL plakt. Als je er ook maar eentje mist heb je al een SQL injection mogelijkheid op je website!</p>
@ -123,7 +123,7 @@
<p class="hint"><strong>Hint:</strong> Maak er een query van die alle gebruikers teruggeeft, de site logt dan in als de eerste gebruiker. Het maakt voor de opdracht niet uit als wie je inlogt.</p>
<div class="question">
<span class="question-string">Bekijk de <a href="https://github.com/Avans/Security-Workshop/blob/master/bank/index.php#L51" target="_blank">PHP broncode</a> en los het probleem op. Type de regels code die je verbeterd hebt in onderstaand tekstveld. (denk terug aan je mysql WEBS2 practicum)</span>
<span class="question-string">Bekijk de <a href="https://github.com/Avans/Security-Workshop/blob/master/bank/index.php#L51" target="_blank">PHP broncode</a> en los het probleem op. Type de verbeterde regels code in onderstaand tekstveld. (denk terug aan je mysql WEBS2 practicum)</span>
{% include "points.html" with points=answers.answer_sql_fix_query.points max="15" %}
<textarea class="question-input" name="answer_sql_fix_query">{{answers.answer_sql_fix_query.string}}</textarea>
</div>

@ -194,6 +194,8 @@ figcaption {
<p>Ga naar de <span class="website">Wereldwijs (XSS)</span> pagina. Deze site hebben ze helemaal Web 3.0 gemaakt door alle pagina's met Javascript te tonen. Helaas hebben ze het weer niet zo nauw genomen met de veiligheid en zit er een XSS mogelijkheid in de site. Ga op zoek in de broncode van de pagina naar manieren om Javascript uit te voeren op de pagina.</p>
<p>Let op: In Firefox werkt deze hack niet</p>
<p class="hint"><strong>Hint 1: </strong> jQuery wordt op een onveilige manier gebruikt, op internet kan je vinden hoe je dit kan uitbuiten.</p>
<p class="hint"><strong>Hint 2: </strong> Met de $('') functie van jQuery kan je ook nieuwe DOM elementen maken Bijvoorbeeld: $('&lt;div&gt;'). Deze versie van jQuery vindt het niet erg als daar ook nog een # voorstaat.</p>

@ -6,7 +6,8 @@ from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User
from django.contrib import messages
from quiz.models import Answer
from django.db import connection
from quiz.models import Answer, LetsEncryptChallenge
import oauth2 as oauth, cgi, json, base64, urlparse, subprocess
from oauth2_provider.views.generic import ProtectedResourceView
import securityquiz.secrets as secrets
@ -132,6 +133,59 @@ 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
@ -211,3 +265,20 @@ tq9DcELddZK2gJXaXpL1wOL+Ex5RzzRmjqKmmkkn1//ikn+nrZU=
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')
Loading…
Cancel
Save