We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Sichere Webanwendungen mit Clojure

00:00

Formale Metadaten

Titel
Sichere Webanwendungen mit Clojure
Serientitel
Anzahl der Teile
84
Autor
Lizenz
CC-Namensnennung 3.0 Unported:
Sie dürfen das Werk bzw. den Inhalt zu jedem legalen Zweck nutzen, verändern und in unveränderter oder veränderter Form vervielfältigen, verbreiten und öffentlich zugänglich machen, sofern Sie den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen.
Identifikatoren
Herausgeber
Erscheinungsjahr
Sprache

Inhaltliche Metadaten

Fachgebiet
Genre
Abstract
In diesem Vortrag praesentieren wir Clojure als eine mögliche Sprache um mit wenig Aufwand sichere Webapplikationen zu bauen. Wir zeigen dabei mit welchen Features gängige Frameworks verschiedene Angriffe verhindern und zeigen, dass "Security" ein grundlegender Teil der Architektur sein muss. Joy Clark, Simon Kölsch
ClojureFunktion <Mathematik>Funktionale ProgrammierspracheProgrammierungDatenmodellSIMPL <Programmiersprache>XMLUMLVorlesung/KonferenzComputeranimation
ClojureDatenstrukturProgrammierspracheReiheVektorrechnungFunktion <Mathematik>AnwendungssoftwareHebelMomentenproblemZahlenbereichSummeVersion <Informatik>ParametersystemOrbit <Mathematik>Formation <Mathematik>HochgeschwindigkeitsnetzDrupalOrganic ComputingCross-site scriptingBASICOrdnung <Mathematik>StichprobeZeichenketteFRAMEWORK <Programm>MAPWEBVorlesung/KonferenzComputeranimation
FRAMEWORK <Programm>ParametersystemWeb-AnwendungEigenwertproblemEXCELTabelleVerschlingungPILOT <Programmiersprache>Ein-AusgabePOWER <Computerarchitektur>Mailing-ListeIntranetSoftwareschwachstelleWeb-ApplikationCodeNabel <Mathematik>HomepageHyperlinkVorlesung/KonferenzComputeranimation
AlgorithmusEinfache GenauigkeitVorlesung/Konferenz
DatensichtgerätFRAMEWORK <Programm>Computeranimation
Geometrischer KörperExogene VariableRoutingRouterBrowserSchreib-Lese-KopfWeb-ApplikationImplementierungAnwendungssoftwareGrundraumServerFormation <Mathematik>InternetIntranetVorlesung/KonferenzComputeranimation
Ein-AusgabeValidierungHTMLWeb-AnwendungDefaultElementare ZahlentheoriePasswortGraphiktablettVorlesung/KonferenzComputeranimation
ZeichenketteCross-site scriptingImplementierungTemplateDatenbankToken-RingServerZugbeanspruchungEin-AusgabeWort <Informatik>JavaScriptSkript <Programm>Web logWald <Graphentheorie>KryptoanalyseDatenbanksystemMiddlewareQuellcodeVorlesung/KonferenzComputeranimation
InformationRechnenAnwendungssoftwareFaktorisierungChipkarteAuthentifikationPasswortAutorisierungVorlesung/Konferenz
AlgorithmusBASICDatenbankInformationFunktion <Mathematik>MittelungsverfahrenZugriffFlächeMittelwertCHART <Programm>DateiToken-RingParametersystemFehlermeldungRoutingDesigner <Programm>AuthentifikationKomponente <Software>PasswortAutorisierungMAPAbfrageAPIComputeranimation
MittelungsverfahrenFehlermeldungAuthentifikationAutorisierungDefaultVorlesung/Konferenz
DatenbankImplementierungInformationOrdnung <Mathematik>ReiheWelleZahlMittelungsverfahrenTabelleVersion <Informatik>EckeParametersystemHomepageJavaScriptBrowserHTTPContent <Internet>Cookie <Internet>StandardabweichungDefaultCross-site scriptingGroße VereinheitlichungInverser LimesLastServerKontrollstrukturWeb SiteWeb ServicesLoginComputeranimation
SystemidentifikationServerHash-AlgorithmusRundungJavaScriptBrowserSkript <Programm>QuellcodePlug inCDN-NetzwerkCross-site scriptingDomain-NameProviderContent <Internet>Vorlesung/Konferenz
VerschlingungServerGraphische BenutzeroberflächeHTMLJavaScriptBrowserSkriptspracheApache <Programm>Explosion <Stochastik>Twitter <Softwareplattform>Internet ExplorerFirefox <Programm>Computeranimation
AnwendungssoftwareMomentenproblemRang <Mathematik>Graphische BenutzeroberflächeQuellcodeFirefox <Programm>JavaScriptPlug inVorlesung/Konferenz
ClojureAnwendungssoftwareTwitter <Softwareplattform>CW-KomplexKonfigurationsraumAuthentifikationSage <Programm>ComputeranimationVorlesung/Konferenz
Computeranimation
Transkript: Deutsch(automatisch erzeugt)
Also, hallo zusammen. Danke, dass ihr so zu unserem Vortrag kommt. Ich bin die Joy, das ist der Simon. Und heute wollen wir über Web-Sicherheit in Clojure reden.
Also, wir wollten einfach ein bisschen einen Crash-Cross machen. Wir wollten fragen, wer in diesem Raum schon Clojure, was mit Clojure gemacht hat. Und so ein bisschen, oder List-Dialekt. Ich weiß nicht, ob das es besser macht. Für das Verständnis ein bisschen, weil das nämlich eine List-Variante ist, die auf der JVM läuft.
Wir werden nicht zu sehr an der Sprache, so die Sprache, zu viel darüber reden, weil wir auch sehr viel über Web-Sicherheit zu sagen haben. Deswegen können wir das nicht so ausführlich erklären. Wir wollen aber so einfach einen grober Überblick in die Sprache jetzt geben.
Das ist eine funktionale Programmiersprache und es hat einen sehr simple Programming Model. Das Wort möchte ich dabei betonen, dieses Wort simple, in Sinne von nicht verflechtet. Also, die Idee in Clojure ist, dass man versucht, Daten, die man hat, von Verhalten zu trennen.
Also, das Verhalten von einem Programm wird über Funktionen beschrieben. Und dann kann man mit einer Funktion irgendwie Daten verändern und neue Daten bekommen. Und dabei kann man die Applikation so gestalten, dass es weniger verflechtet ist.
Die Data Structures in Clojure sind immutable, das heißt nicht veränderlich. Und es sieht so ähnlich aus. Das ist eine Clojure Map, wo man als Keys so Keywords haben kann. Das ist dieser Name, Features, Creator, das sind alle Keywords. Man kann Strings haben, Vektoren oder man kann das beliebig verschachteln innerhalb von der Datenstruktur, innerhalb von dieser Maps.
Syntaktisch gesehen wird alles, was zusammengehört, in Klammern gruppiert. Und es ist Präfixnotation, das heißt, dass die Funktion, die aufgerufen wird,
an erster Stelle innerhalb von den Klammern so vorkommt. Also in diesem Fall rufen wir die Funktion plus auf mit drei Argumente 1, 2, 3. Und daraus bekommen wir die Summe über alle Zahlen. Man kann auch Keywords als Funktion benutzen.
Wenn man ein Keyword als Funktion benutzt, schlägt der Keyword sich selber in eine Map und liefert, dass ergebnisweise eine vorhanden ist. Man kann dann auch diese Funktion in eine Higher Order Funktion stecken, denn man kann diese Funktion überall durchreichen. Und wenn man das in eine Higher Order Funktion zum Beispiel wie Map anwendet,
bekommt man diese Funktion auf alle Elemente in der Sample Collection angewendet. Wenn man über Web Security redet, landet man immer ziemlich schnell bei den OWASP Top 10.
Das OWASP Wiki ist eigentlich eine Sammlung von Best Practices und Empfehlungen, wie man denn Anwendungen baut im Web. Das bezieht sich nicht auf eine bestimmte Programmiersprache. Und man kann da immer so ein bisschen die Frage stellen, okay, diese OWASP Top 10, die sind von 2013,
da steht immer noch Injection, den XKCD Comic mit Little Bobby Tables haben wir uns jetzt gespart. Der ist irgendwie von 2007, kennt dann wahrscheinlich auch fast jeder. Da taucht immer noch so was auf wie Cross-Site-Scripting, wie gesagt Injection-Attacken, CSURF ist mit dabei.
Und da ist durchaus die Frage berechtigt, ist das tatsächlich noch irgendwie relevant? Also macht das nicht inzwischen ganz normal das Framework, was ich einsetz? Die OWASP Top 10 2016 sind noch nicht raus, aber im Moment gibt es da eine aktualisierte Version, die kommt irgendwann im Laufe des Jahres.
Wir sind mal gespannt, ob sich da irgendwie diese Top 10 Reihenfolge verändert hat. Wenn man sich jetzt so Advisories anschaut, das ist jetzt irgendwie Symphony, ein relativ populäres PAP Framework, da findet man auch Session Fixation, das ist jetzt von 2015, vom November. Da muss man aber nicht bei PAP bleiben, das zieht sich durch Python mit Rupal auch durch.
Das ist auch Cross-Site-Scripting mit dabei, wenn man aufs Datum guckt, das ist jetzt vom Juli 2016. In Ruby Core gab es eine Änderung, woraufhin für GitLab, die Ruby nutzen, auch direkt drei Advisories rauskamen.
Das ist dann auch wieder Cross-Site-Scripting mit dabei, Kleinigkeiten in Basic Out. Und wenn man dann zu Java rüberguckt mit Wicket, eigentlich völlig egal, welches Framework man sich da anguckt, findet man hier auch ein Core von April diesen Jahres, auch wieder Cross-Site-Scripting. Das heißt, die Probleme sind tatsächlich auch immer noch relevant und das sind nicht die Anwendungen, die die Leute gebaut haben,
sondern das sind die Probleme, die im Core Framework mit drin sind. Das heißt, so ein bisschen die Vorstellung, sichere Web-Anwendungen bekommt man dadurch, indem man irgendwo den Parameter Secure anschaltet oder irgendwie sowas, wenn man im Java-Spring-Umfeld sich bewegt, sowas wie Spring Security benutzt
und damit wird die Anwendung automatisch sicher, das funktioniert nicht. So ein Framework kann nicht irgendwie alle Probleme lösen. Und ich persönlich fand das eigentlich ein ganz nettes Beispiel, da ist die Idee, dass man so ein CSV-Injection macht. Man kennt das vielleicht irgendwie, man diskutiert mit einem Fachbereich und der sagt irgendwann,
ich hätte gerne diese Tabelle aus der Web-Anwendung in meinem Excel drin. Und dann baut man irgendwo so ein CSV-Export ein und dann fällt da einfach ein CSV-File raus. Das Problem an der Stelle ist, man prüft vielleicht irgendwo den Input vom User auf irgendwelche HTML-Texts und eskept die.
Man prüft aber vielleicht nicht, ob da sowas wie ist gleich Hyperlink mit drin steht in irgendeinem Freitextfeld. Und das würde jetzt zum Beispiel in dem importierten CSV-File einfach einen Link erzeugen in dem Excel auf irgendeiner Homepage. Das kann man dann beliebig irgendwie weiterspielen. Man kann dann irgendwie den Windows-Calculator starten, indem man einfach die Textfolge drin hat.
Natürlich fragt der Excel nochmal nach. Mit dem Importieren stammt irgendwie das CSV-File aus einer vertrauenswürdige Quelle. Tut's ja, ich hab's ja aus meinem Intranet aus der Anwendung gerade runtergeladen. Und wenn man das noch ein bisschen weiterspielen will, das würde jetzt aus einem Netz eine Payload runterladen,
die eine Reverse-Shell aufmacht, das Ganze in ein Execution-Commandlet stecken und über die Power-Shell starten. Das funktioniert natürlich nicht einfach so, man muss da durchaus Admin sein. Man muss irgendwie die VGET-Extension aktiviert haben. Das sind alles verschiedene Bedingungen, die dazutreffen müssen, dass das wirklich funktioniert.
Aber ich hab einen Freund gebeten, das auszuprobieren, weil ich passendes Excel jetzt nicht da hatte. Und der meinte dann auch, ja, da braucht ja der User Admin-Rechte. Also er hatte Admin-Rechte. Das kommt also vor und im Angreifer ist es eigentlich ziemlich egal, ob von den 200 Usern das nur bei 10 funktioniert. Also wenn es bei 10 funktioniert, hat er 10 Shells danach.
Und das soll einfach ein Beispiel sein, dass selbst wenn man im Framework irgendwie alle Validation-Rules und Escaping anhat, das sind Dinge, die kann ich nicht automatisiert lösen. Da muss ich irgendwie mich hinsetzen und mir das angucken. Das heißt, um wirklich eine sichere Web-Anwendung zu bekommen, einfach einen Einstieg, bevor wir ein bisschen mehr auf Closure eingehen.
Security ist Teamwork. Man muss irgendwie zu einem Prozess kommen, dass man im Team darüber spricht, dass es nicht so ein Finger-Pointing ist, da hat jemand irgendwie einen Bug eingebaut, sondern dass es wirklich, wenn man vielleicht eh regelmäßige Reviews hat, das ein Thema wird.
Und jeder macht Fehler. Und man kann sich noch so viel irgendwie über zum Beispiel SQL-Incheckchen aneignen. Irgendwann hat man vielleicht doch mal Stress und irgendwie einen Produktionstermin und dann rutscht einem doch mal was durch in einer relativ komplexen Maske, wo man irgendwas ans Ring dranhängt.
Und da ist niemand davor irgendwie gefeit und deswegen hilft das einfach, wenn man Reviews vom Code macht und zwar mit zwei Leuten einfach regelmäßig. Und das versucht, als festen Prozess zu etablieren. Zusätzlich zu diesem magischen Framework, was einem dann vielleicht ein bisschen weiterhilft. Das heißt, wenn man das so ein bisschen zusammenfassen will, man muss sich um seine Anwendung kümmern.
Das heißt, regelmäßig auch die Libraries hochziehen, die Versionen. Es macht Sinn, da normalerweise haben die meisten Projekte irgendwie Advisory Mailing Liste, die man abonnieren kann. Da bekommt man relativ schnell eine Info über irgendwelche Sicherheitslücken und kann halt dann entscheiden, muss ich das sofort patchen oder hat das einfach auch noch eine Woche Zeit.
Keep it simple, stupid ist so das, was man sowieso ständig hört. Das gehört so ein bisschen zusammen mit know what you're doing. Man findet das ganz oft, dass irgendwo im Unternehmen dann O-Out benutzt werden soll, weil das ist dann so die Vorgabe, das ist jetzt so das neue Single sein on.
Und irgendwie von den zehn Leuten im Team verstehen neun eigentlich nicht, was da passiert. Und einer ist so ein bisschen der Security Beauftragte und der kümmert sich dann darum, dass irgendwie dieses O-Out funktioniert. Und vielleicht macht es Sinn, in so einem Umfeld dann ein Stück zurück zu gehen und einfach eine einfache Methode zu wählen.
Ich sage damit nicht, dass man einfach jeden Algorithmus selbst bauen soll, weil es halt einfacher ist, aber dass die Leute im Team einfach wissen, was sie da tun. Weil nur, wenn ich eigentlich weiß, was da passiert, kann ich auch irgendwie dafür gerade stehen, dass das halbwegs sicher ist. Und so der letzte Punkt, der immer so ein bisschen vergessen wird,
das hängt oft damit zusammen, dass Projekte halt als Projekt strukturiert sind und selten dann irgendwie weiter gepflegt werden, ist einfach, dass man sich um die Applikation kümmert, indem man die auch monitort. Normalerweise habe ich einen Betrieb, der macht vielleicht irgendwie Monitoring. Das macht trotzdem Sinn, in die Lockfiles mal reinzugucken.
Das muss man nicht ständig machen, aber regelmäßig vielleicht einmal, wenn es nur einmal im Monat ist, sich mal eine Stunde hinsetzen und gucken, wie verhält die Anwendung sich, und zwar unter realen Bedingungen. Was passiert da eigentlich? Und sind diese Lockeinträge denn jetzt normal, die ich hier sehe, oder sind die ein Problem und habe ich hier vielleicht irgendwie ein seltsames Verhalten
und seltsames Kettern? Und da einfach ein bisschen informierter sein, was passiert da eigentlich, wenn die Anwendung in Betrieb läuft. Das sind so einfach so ein paar grundlegende Tipps, wie man vielleicht zu einer sichereren Anwendung kommt, ohne dass man da jetzt tief in irgendwelche Libraries oder Frameworks einsteigen muss.
Also jetzt kommen wir jetzt zum Clojure-Teil, nämlich wie können wir mit Clojure-Web-Applikationen zusammenbauen? Also was es in der Clojure-Web gibt, ist Ring. Das ist eine HTTP-Server-Abstraktion, die von der Clojure Community entwickelt wurde.
Und das wird als Standard gesehen. Das Schöne daran ist, dass die Leute, die Web-Applikationen in der Clojure-Welt entwickeln, halten sich an diesem Standard und das, was tatsächlich als HTTP-Server unten drunter liegt,
kann beliebig ausgetauscht werden. Zum Beispiel gibt es einen Adapter für Jetty. Also das ist alles auf der JBM. Also wir haben alle Java-HTMS-Server zu Verfügung. Es gibt einen Adapter für Jetty, für HTTP-Kit und so weiter. Für Routing hat man Composure oder andere Bibliotheken. Die Bibliothek, die wir in diesem Vortrag heute präsentieren, ist Composure.
Und diese Ring-Standard, was wir haben, in diesem Standard sind die Requests und die Responses. Die sind Daten, sie sind Clojure-Maps, die bestimmte Keywords drin haben, die dann gemapped werden zu den HTTP-Requests und Responses.
Und die Web-Applikation selber ist nur eine Funktion, die eine Request annimmt und einen Response zurückliefert. Also das ist so ein Beispiel dafür. Das ist ein Beispiel für ein Example-Request in Ring. Es hat drei Keywords, die Pflicht sind für ein Ring-Request.
Das sind die URI-Request-Method und die Headers, die es gibt für den Request. Und man kann dann ein Beispiel-Applikation, einen Response zurückliefern. Der Standard und Ring für den Response sind Status und Body.
Die zwei Keywords müssen drin sein. Und wenn man sich daran hält, dann ist das eine valide Ring-Applikation. Man möchte natürlich nicht alles selber zusammen basteln, aber man kann mit Composure dann deklarativ die Routen für die Applikation definieren.
Zum Beispiel mit Get, Post, so wie die Methode, die man dann hat, die URI. Man kann dann die Request, das ist hier die Request, und dann das entsprechend an eine Funktion, die man selber schreibt, überreichen. Und diese Funktion kümmert sich dann um diese Request, was ankommt.
Also man kann dann auch in diese Deklaration ein bisschen Destructuring von den Request machen, um die richtige User-Input zu extrahieren. Was dann wichtig ist vor allem im Web-Sicherheit ist, was oben drüber kommt.
Weil es gibt den Ring-Middleware, das ist so ein Web-Puffung, wodurch die Request dann gereicht werden, wo man die modifizieren kann, bevor man sie an eine Web-Applikation schickt. Oder man kann sie ändern, bevor man sie zurückgibt.
Und das ist vor allem wichtig, wenn man bestimmte Header immer setzen möchte in seine Request oder Responses. Und man möchte das nicht für jede, so selber in jede von diese kleinen Funktionen, die ihr schreibt, man möchte das nicht selber machen. Man kann das auf so eine Weise machen.
Und dann die einfach so in unserer Web-Applikation, diese Web-App alle zusammen kombinieren. Und dann wird das entsprechend aufgebaut. Also ein Overview. Das, was geliefert wird im Clojure-Universum, ist von der Java-Seite kommen diese ganzen Server-Implementierungen.
Jetty oder HTTP-Kit oder die sind schon da. Darauf basiert Ring, das kommt aus der Clojure-Universum. Man hat da Mittelware dazwischen und Composure oder eine andere Routing-Bibliothek für Routing. Und das, was man selber schreiben muss, ist dann dieser Händler ganz unten.
Das sind einfach kleine Funktionen, die meistens so eine Request, also abarbeitet und etwas sinnvolles zurückgibt. So HTTPS, unser Punkt ist, dass es das gibt. Und man sollte das benutzen. Es gibt keinen Grund heutzutage, kein HTTPS zu benutzen.
Oft sagen Menschen, ach, ich möchte aber nicht, weil dann brauche ich ein Zertifikat. Und wenn ich jetzt mit HTTPS starte, kann ich dann nicht auf die Seite zugreifen. Mein Browser erlaubt mir das nicht. Aber zum Beispiel mit Jetty kann man sehr einfach im Internet googeln.
Und dann findet man, wie man ein Zertifikat generiert und wie man das zu deinem Keystore packen kann und wie das dann entsprechend einfach in den Konfigurationen von der Web-Applikation machen kann. Man sagt dann manchmal, aber es gibt ein Reverse-Proxy davor und das hat HTTPS. Also muss ich mich nicht darum kümmern.
Aber es kann sein, dass das innerhalb von deinem Intranet, wo diese Web-Applikation laufen lässt, dass es trotzdem in diesem Umfeld ein Man-in-the-Middle-Attacke hat. Deswegen sollte man einfach auch HTTPS benutzen. Der Hauptpunkt bei Web-Sicherheit ist das Validate-Input-Escape-Output.
Also dass man das Input von einem Benutzer immer validieren soll, dass es etwas Vernünftiges ist. Und bevor man irgendwas mit den Daten macht, dass man das vernünftig eskebt, um alles rauszufiltern, was so schädlich sein könnte. Man sollte niemals dem Benutzer vertrauen. Das wäre der erste Fehler, den man macht.
Also zum Beispiel für Validierung in der Closure-Umwelt gibt es Bouncer. Das ist eine Bibliothek für die Validierung von Benutzern. Das nimmt einfach die Werte, die man von einem Benutzer bekommt und gibt sinnvolles Feedback, die man dann in einer Web-Anwendung benutzen kann.
Zum Beispiel man braucht ein Username und Passwort, sonst ist das ungültig. Also Escape-Output ist auch wichtig, das ist der zweite Punkt. Und in diesem Fall reden wir über HTML-Escaping. Und das heißt, wenn ich mit Templating-Engine möchte,
möchte ich etwas hinzufügen von einem Benutzer. Der Benutzer hat seinen Namen angegeben. Ich möchte das rendern in meinen HTML-Seite. Selmer in diesem Fall ist ein Templating-Library in Closure. Und wenn man Selmer das rendert, ersetzt er alle eckige Klammern
und alle Zeichen, die Probleme sein können für HTML durch die entsprechende Ersetzung. Das ist wichtig und etwas sehr Wichtiges ist, das sollte eigentlich per Default passieren in alle vernünftigen Templating-Engines.
Einfach immer, das sollte einfach drin sein. Das ist in Closure nicht der Fall, das sollte man wissen. Vor allem Hiccup, was der am häufigst verwendete HTTP-Bibliothek, hat es nicht per Default.
Also per Default wird es einfach reingerendert. Das wird von einem Benutzer nicht esgebt, bevor das reingerendert wird. Man bräuchte dazu eine externe Funktion. Ich würde persönlich HBS, das ist eine Handlebars-Implementierung für Closure, oder Selmer, das ist eine Django-basierte Templating-Sprache für Closure.
Einen von denen würde ich an der Stelle empfehlen, weil mit Hiccup das ohne Escaping nicht so gut funktioniert, finde ich fürchterlich. Der Grund, warum man das braucht, ist nämlich XSS, das heißt Cross-Site Scripting.
Das ist, wenn man irgendwie einen String von einem Benutzer bekommt, meistens die bösen Tags sind die Script-Tags. Wenn das reingerendert wird, gibt es dann valide Inline-Java-Script, was dann, sobald diese Seite gerendert wird, ausgeführt wird. Und man sagt, ja, ja, aber wenn der Benutzer seine eigene Benutzenname doof umbenennt,
wem soll das interessieren? Aber das hat vor allem im Bereich von Webforen oder Blogs, wo der Benutzer beliebige Kommentare schreiben kann und die bei jedem, jedes Mal, wo die Seite geladen wird, alle angezeigt werden und alle gerendert werden, dann wird für jede Person, die darauf geht, die Seite, also wird dieses Script ausgeführt.
Und man kann dann alles machen, was in JavaScript geht, was ziemlich viel ist. Man kann zum Beispiel C-Server-Tag machen oder irgendwas anderes. Aber C-Server steht für Cross-Site Request Forgery.
Und es handelt sich vor allem darum, dass der Benutzer irgendwelche Request irgendwo schickt, ohne zu wissen, dass er das getan hat. Zum Beispiel, man kann das machen, indem der Source in der Image-Tag auf irgendwas gesetzt wird, sodass irgendwie ein Get-Request losgeschickt wird zu dieser anderen Seite.
Es kann auch über ein Formular, was heimlich zugefügt wird, wo der Benutzer zufällig darauf klickt, dieses Formular dann losschickt an irgendeinem Server irgendwo. Und das typische Beispiel dafür ist, dass vielleicht bist du bei deiner Bank angemeldet und Angriffe kann dich so verursachen, dass du ihm ganz viel Geld beweist oder so.
Wie man dagegen vorgeht, gegen C-Server, ist, dass man sagt, auf der Server-Seite generiere ich mir ein Geheimnis, was der Benutzer nicht weiß. Also ich generiere mir ein Geheimnis für den Pro-Benutzer.
Und das rendere ich rein in mein Formular. Und jedes Mal, wenn dieses Formular, dieses Postrequest ankommt, prüfe ich, dass dieses Geheimnis stimmt. Dass das das ist, was ich in diesem Formular so reingerendet habe, dann vertraue ich, dass dieses Formular wirklich von mir kommt.
Natürlich, wenn man XSS drin hat und der Benutzer so zufällige Token extrahieren kann aus dem Formular und irgendwo anderes reinpacken, dann hat man verloren. Aber das hilft erst mal dagegen. Also in Clojah gibt es eine Bibliothek Ring, Middleware, Anti-Forgery.
Man kann da diese Anti-Forgery-Token generieren. Das wird an dem Nutzer und an dem Session gebunden. Und dann der Ring Middleware kümmert sich darum, bei jeder Postrequest zu prüfen,
dass es dieses Anti-Forgery, ja, das wird so reingerendet in dem Formular. Man muss das selber machen, dass das richtig in dem Formular vorkommt, das Token mit dem Wert. Und Ring prüft, also standardmäßig diese Parameternahme fragt er ab und stellt sicher, dass der Token, was da reingerendet wurde in der Formular,
passt für den Benutzer in dem eingeloggten Session. SQL-Injection, das wurde schon längst gelöst eigentlich. Das ist wenn man so Benutzer-Input, also quasi wenn man Queries mit String-Konkatenation zusammen bastelt,
dann zum Beispiel, so gibt es, ja, kann man ganze Datenbanken und so rauslesen einfach. Das sollte man aber nicht tun, das wurde schon längst gelöst. Clojure, die SQL-Bibliotheken basieren alle auf JDBC in der Java-Umwelt, das gibt es schon länger.
Das sollte man einfach benutzen. Es gibt verschiedene Bibliotheken in Clojure, die auf dem JDBC drauf so basieren. Zum Beispiel Yescule, dass das erlaubt, ein bisschen schöner aufzuschreiben und zu benutzen. Also, das ist ein gelöstes Problem und man sollte es nicht mehr, ja.
Authentifizierung und Autorisierungen sind immer so zwei Punkte, die ganz oft vermischt werden.
Aus so einer Architektursicht haben die zwar was miteinander zu tun, aber es gibt durchaus Gründe dafür, das auch sinnvoll ein bisschen zu trennen. Authentifizierung ist einfach, ist der Benutzer, wer sagt, dass er das ist. Da kann ich auch verschiedene Methoden authentifizieren.
Also denkbar ist ganz normal Benutzername, Passwort. Es kann aber durchaus sein, dass es irgendwie relevant ist, dass ich da nochmal unterscheiden will. Hat er sich mit einem zweiten Faktor noch mit authentifiziert? Hat er vielleicht eine Smartcard gehabt, die erst nicht im Rechner drin war, aber an dem Teil in der Anwendung hätte ich jetzt dann doch gerne Authentifizierung via Smartcard.
Das heißt, ich habe unter Umständen mehrere Backends gegen die ich authentifizieren will. Und Autorisierung ist einfach die Information, okay, jetzt weiß ich, das ist wirklich der Benutzer. Was darf der denn eigentlich? Und da gibt es auch eine ganze Sammlung an Libraries, die das in Closure-Web-Applikationen machen.
Ich fand ehrlich gesagt bis jetzt so am besten und am benutzbarsten und vor allem am besten dokumentiert. Also ich lese ungern Doku, weil die meistens sehr anstrengend sind. Bei Buddy fand ich die eigentlich ausgesprochen gut. Das ist ein Security-Framework einfach für Closure. Das hat ein Buddy-Core, da sind die ganzen Algorithmen und so weiter implementiert.
Und dann quasi drei Module, auf die das aufbaut. Und zwar einmal Buddy-Out, da steckt dieser ganze Autorisierungs-Authentifizierungsteil drin, die entsprechende API. Es gibt Buddy-Hashers. Wenn man hingeht und ein Passwort von einem Benutzer entsprechend gehasht in der Datenbank packen will,
habe ich da die passenden Funktionen dafür. Da habe ich auch so Dinge drin wie sinnvolles Padding von kurzen Passwörtern, um die erst anschließend zu haschen. Und es gibt Buddy-Sign für so Dinge wie z.B. Job-Tokens. Da möchte ich dann irgendwie meinen Token vielleicht signieren oder noch verschlüsseln,
wenn der Benutzer den Inhalt nicht sehen soll. Das ist unter Buddy-Sign dann zu finden. Buddy-Out ist eine Integration als Ring-Mittelwehr. Das heißt, wenn ich eh Ring einsetze, was sehr wahrscheinlich ist, kann ich einfach Buddy darin benutzen.
Die ganzen Authentifizierungs-Informationen über den Nutzer werden in den Request gepackt. Das heißt, ich habe eh immer meine Request-Map in dem Ringumfeld. Und da habe ich, wenn ich Buddy einsetze, eine zusätzliche Key, der nennt sich Identity, und darin befindet sich dann nochmal eine Map mit den Authentifizierungs-Informationen.
Es gibt verschiedene Backends, die schon mal so direkt mitkommen. Also HTTP-Basic-Out kennt man. Man kann ganz normal die Ring-Sessions mit Buddy zusammen benutzen. Das funktioniert ohne Probleme. Ich habe die Möglichkeit, beliebige Tokens zu benutzen. Es gibt Signed-Jots, es gibt Encrypted-Jots.
Also das kommt schon irgendwie von Haus aus mit. Mir fällt da auch nicht ehrlich gesagt direkt mit ein, was da noch fehlen sollte. Wenn einem trotzdem dann nochmal eine Variante fehlt, die man wirklich zur Authentifizierung benutzen will, gibt es immer noch die Möglichkeit, einfach dieses Protokoll von Buddy zu implementieren,
zum Beispiel über ReFi, und das dann einfach selbst umzusetzen. Das ist ein relativ einfaches Beispiel aus der Doku. Also sollte da mal jemand reingucken, kommt ihm das vielleicht bekannt vor. Das ist einfach eine Basic-Out-Authentifizierung.
Und was wir hier direkt am Anfang sehen, ist die Definition von einer eigenen Authentifierungsmethode. Das heißt, zum einen will ich ja irgendwie Credentials vom Benutzer abfragen. Das macht Buddy in dem Fall für mich, eben hier über diese Basic-Out-Variante. Zum anderen muss ich dann ja tatsächlich die Überprüfung gegen generisches Backend machen.
Sei das irgendwie eine Datei mit Benutzernahme und Passwort, sei das irgendwie die LWAP-Authentifizierung. Ich bekomme hier als Parameter einfach den Request mit übergeben und die entsprechenden Authentifizierungs-Credentials. Da steckt in dem Fall bei Basic-Out Benutzernahme drin, ein Passwort drin.
Ich würde in dem Fall dann einfach das Ganze überprüfen. Und ich muss ein logisches True zurückgeben. Und letztendlich ist das die Information, die in meiner Identity-Map landet, die an jedem Request annotiert wird. In dem Fall wäre es einfach der Benutzernahme. Und hier unten sehen wir dann nochmal die Definition von diesem Basic-Out-Backend
mit den entsprechenden Parametern. Und hier ist dann die Referenz zu meiner eigenen Funktion hoch. Authorization funktioniert ähnlich. Wir haben diese Composure-Rooting-Komponente. Und genauso werden hier mit Buddy-Access-Rules definiert.
Das heißt, ich annotiere einfach wieder meine Ressource, die ich irgendwie schützen möchte. Zum Beispiel Slash-Users. Annotiere die Methode, die ich da drauf noch habe. Und einen entsprechenden Händler, mit dem ich dann tatsächlich diese Authorisierung überprüfen möchte. Da kommt ein Satz von Standard-Händlern mit. Zum Beispiel einfach Authenticated.
Das würde jetzt genau das tun. Dann kann man in die Identity-Map gucken und da ein True oder False zurückgeben. Dann bekommt der Benutzer Zugriff darauf. Es ist aber auch möglich, einen eigenen Händler zu definieren. Das wäre jetzt dieses Is-User. Man bekommt immer den Request mit übergeben. Der Request wird dann gepasst.
In dem Fall jetzt hier als Beispiel. Der User wird rausgeholt aus dem Identity-Layer. Und es wird einfach dann gematcht. Dann steckt da ein User drin. In dem Fall geben wir True zurück und haben dann hier den eigenen Händler an der Stelle.
Das Ganze müssen wir als Mittelwehr in diesen Ringstack mit reinbringen. Das wäre dann das Beispiel dafür, wie man diese Mittelwehr mit dazu bringt. Man kann eine eigene Error-Redirect-Methode definieren. Die Händler bringen das aber normalerweise selbst mit.
Dieser Basic-Out-Händler würde dann einfach nochmal Benutzernamen, Passwort abfragen oder auf eine entsprechende Seite redirecten, je nachdem, wie der konfiguriert ist. Ich kann das aber direkt auch selbst machen, habe dann irgendwo meine Mittelwehr-Definition und habe an der Stelle die Funktion Wrap Access Rules.
Hier wird eine Map übergeben und würde dann über den Key Rules diese von mir definierten Access Rules mit übergeben. Hier an der Stelle überschreibe ich mit OnError einfach das Default Error-Verhalten mit diesem Error-Redirect. Und die Authentifizierung würde man dann einfach mit,
vorher haben wir eine Funktion ab Define Backend, würden wir jetzt mit Wrap Authentication mit in diese Mittelwehr reinbringen. Und dann hat man an der Stelle eigentlich schon Autorisierungen und Authentifizierungen in diesem Ringstack mit benutzt.
Also was man auch beachten muss, wenn man über Web-Sicherheit redet, ist, dass wenn Redirects innerhalb von der Applikation so stattfinden können, sollten sie nicht unvalidiert einfach losgeschickt werden,
weil die zum Beispiel als Redirect-Proxy benutzt werden könnte. Man kann das in Clojure sehr einfach machen, falls man zu irgendwo redirecten möchte, das typische Beispiel ist bei Login, wenn man von irgendeiner Seite zu Login redirectet wird, möchte man nach einem erfolgreichen Login zurück
zu der ursprünglichen Seite redirectet werden. Man kann das aber so, bevor man diese Redirect los schickt, einfach überprüfen, dass das mit einem Whitelist übereinstimmt von erlaubten Seiten. Und wenn nicht, dann redirectet man einfach zu der Homepage oder sowas.
Man soll natürlich auch den Denial-of-a-Service-Attacken im Hinterkopf behalten. Das ist mehr ein Architekturproblem. Meistens. Den Denial-of-a-Service-Attack ist nur, wenn der Angreifer es schafft,
einen Service so unavailable zu machen. Das kann passieren, wenn der Angreifer sowieso mehr Ressourcen hat wie du. Wenn das der Fall ist, hast du sowieso verloren, sorry. Aber es kann auch so verursacht werden,
wenn du als Opfer mehr Ressourcen brauchst, um einen Request abzuarbeiten, als der Angreifer es schickt. Dann kann er ganz viele von diesen Requests los schicken. Und dein Last ist viel höher, als das, was er braucht, um sie zu schicken.
Solche Fälle sollte man in seine eigene Implementierung schauen, dass das nicht passieren soll. Zum Beispiel naiver Ansatz. Ich habe eine Funktion geschrieben, wo ich dachte, ich möchte durch ein Parameter definieren, wie viele Nachrichten auf einer Seite auftauchen.
Dabei habe ich kein Limit festgestellt. Das heißt, dass ein Angreifer diese Zahl beliebig hochdrehen könnte. Wenn er auf Millionen zugreift, muss ich auf meinen Datenbank Millionen Nachrichten rausholen und dann ihn zurückschicken. Das ist das, was ich mache.
Besser wäre es, sensible defaults zu definieren. Zum Beispiel ein Limit. Wenn ich weiß, es macht überhaupt keinen Sinn, dass der Benutzer irgendwann mehr als 500 auf dieser Seite rendet haben möchte, dann kann ich das einfach limitieren. Und er kann dann nicht verursachen, dass ich beliebig viele Dinge rausholen muss.
Man kann auch mit Sachen wie Circuit Breaker drum herum packen. Circuit Breaker limitiert die Anzahl von Threads, die für eine bestimmte Anfrage benutzt werden können.
Das hilft vielleicht nicht unbedingt gegen Denial-of-the-Service-Attacken, aber es hilft auch, dass du dich danach besser erholen kannst.
Es gibt immer eine ganze Reihe an HTTP-Security-Hattern. Wenn man da in den Ringen mal reinguckt, findet man sowas wie Ring-Defaults. Das sind einfach Standard-Settings für die Mittelwehr.
Das sind dann Hatter, die dann automatisch annotiert werden. Und dann gibt es entsprechende Einteilungen in sinnvolle Defaults für eine API, sinnvolle Defaults für eine normale Homepage und sinnvolle Defaults für eine Secure Site. Damit ist dann gemein, dass da einfach HTTPS davor ist. Da findet man so eine ganze Reihe an Hattern,
die mehr oder weniger hilfreich sind. Was auf jeden Fall eine gute Idee ist, wenn ich in einem Cookie Informationen habe, die ich nicht jemand anderen verfügbar machen will, also mehr als so eine Sort-Order von der Tabelle, sondern vielleicht eine Session-ID oder tatsächlich meine serialisiertes Session,
wenn ich auf dem Server stateless sein möchte, dann macht es Sinn, erst mal zu verbieten, dass dieser Cookie irgendwie über eine HTTP-Verbindung übertragen wird. Dafür gibt es einfach einen Cookie-Secure-Flag. Es gibt außerdem die Möglichkeit, noch mal zu aktivieren,
dass der Cookie auch nur mit normalen HTTP-Requests übertragen wird, also nicht irgendwie per JavaScript, über irgendwie ein indiziertes JavaScript-Request irgendwo hingeschickt wird und plötzlich ist vom Browser dieser Cookie dort im Request enthalten. Es gibt außerdem noch eine ganze Reihe weitere Hatter-Anti-Fortiary-Cross-Site-Scripting-Protection.
Da kann man fragen, wieso ist das nicht standardmäßig irgendwie aktiviert. Meistens wird dieser Cross-Site-Protection-Hatter benutzt, um vom Browser eben Cross-Site-Protection auszuschalten, weil plötzlich mein JavaScript nicht mehr funktioniert.
Nein, ich möchte nicht diktieren. Ich habe die Möglichkeit zu verhindern, dass meine Seite irgendwie woanders eingebunden wird. Dafür gibt es dann diese Frame-Options.
Normalerweise, wenn kein Content-Type für Ressourcen mit angegeben wurde, würde der Browser versuchen, irgendwie den Content-Type zu erraten. Das ist dieses No-Sniff, was man hier als Content-Type-Options, über Content-Type-Options verhindern kann. Wenn meine Anwendung sowieso mit einer Login-Maske
und so weiter funktionieren soll, macht es halt Sinn, einen SSL-Redirect zu benutzen. Das heißt, der Benutzer wird einfach immer auf HTTPS redirected. Das ist allerdings dann ein Problem, wenn ich irgendwie einen Benutzer schon mal auf der Seite hatte. Der hat das Cookie, der ruft die Seite auf. In dem Cookie sind Informationen drin, die ich nicht verfügbar machen will,
und dann ist es aber schon über eine ungesicherte Verbindung übertragen worden. Um sich davor irgendwie zu schützen, gibt es HSTS. Da ist einfach die Idee dahinter, hat der Benutzer einmal die Seite über SSL besucht, wird er in Zukunft auch immer direkt über SSL zu der Seite geleitet. Das heißt, der Browser schickt gar keine HTTP-Requests ab.
Es macht Sinn, auf jeden Fall, sich anzugucken, was haben die Hatter denn für Seiteneffekte und nicht einfach die Defaults zu aktivieren, weil gerade, wenn man vielleicht mal ein Problem mit seiner SSL-Infrastruktur hat und eben schnell mal diesen HSTS-Hatter setzt, ist dann plötzlich die komplette Seite nicht mehr erreichbar.
Da kann man dann argumentieren, dass es nicht mehr besser ist, als dass wir da irgendwie Informationen potenziell für mende Mittel zugänglich gemacht haben. Wenn das aber dann in Firmen fällt, und das blubbert irgendwie blöd beim Management hoch, dann ist da halt sehr schnell, okay, so was wie HSTS schalten wir nie wieder an. Und man hat sich einfach da an der Stelle politisch
die Hatter verbrannt. Von daher auf jeden Fall gucken, was gibt es denn noch so als Hatter, die einschalten, aber halt auch sich dessen bewusst sein, was tut es denn wirklich und was sind denn Seiteneffekte davon. Zu guter Letzt Content Security Policy.
Das Ganze gibt es schon wesentlich länger. Inzwischen ist es schon in der Version 3. Einfach mal so in die Runde gefragt, kennt jemand Content Security Policy? Schon mal irgendwie drübergestolpert oder? Okay, einer. Das ist ein HTTP-Hatter, den man setzen kann.
Und dahinter wird die komplette Policy annotiert. Und dieser Hatter erklärt dem Browser, wie er denn eigentlich mit JavaScript, mit Referenzen auf andere Sources und so weiter umzugehen hat. Es gibt die Möglichkeit, einfach inline JavaScript zu verbieten. Das heißt, wenn ich meine Applikation so entwickle, dass mein JavaScript ordentlich in JavaScript-Files notiert ist,
gibt es eigentlich keinen Grund, dass irgendwo innerhalb von meiner Seite so ein Script Tag auftauchen muss. Und das ist ja tatsächlich genau der Angriffsvektor, der bei Cross-Site-Scripting und so weiter unter anderem benutzt wird. Und damit kann ich dem Browser einfach verbieten, okay, wenn da ein Script Tag kommt, führe den nicht aus.
Ich kann außerdem irgendwie das Verhalten mit Plugins bestimmen. Ich kann zum Beispiel so was wie Flash einfach abschalten. Da kann ein Angreifer so viel Flash Plugins injizieren, wie er den will. Der Browser wird das nicht ausführen. Ich kann festlegen, aus welcher Quelle Sourcen nachgeladen werden, und zwar abhängig vom Content-Type. Das heißt, ich kann bestimmen, dass meine Schriften
nur von einem bestimmten Server oder von einem bestimmten Domain geladen werden. Ich kann bestimmen, dass meine Style-Sheets nur aus einer bestimmten Quelle kommen. Ich kann Hashes für diese Ressourcen mit angeben. Das heißt, selbst wenn in einem CDN so ein Bootstrap-JavaScript liegt, kann ich halt vorher da einen Hash drüber berechnen,
das mit in die Seite aufnehmen. Und selbst wenn dann ein Angriff auf einen CDN-Provider erfolgt und da irgendwie was geändert wird, würde das dann nicht mehr geladen. Und ich habe die Möglichkeit, Nonses mit anzugeben. Das heißt, ich würde an der Stelle Nons generieren, ähnlich wie das CSRF-Token. Und das muss mit in diesem Link im HTML mit angegeben werden,
damit diese Ressource überhaupt geladen wird. Und ich habe die Möglichkeit, einfach diese Content-Security-Policy zu setzen und zu sagen, okay, schalte die nicht aktiv, sondern schick mir nur Reports. Das heißt, der Browser würde bei einem Verstoß gegen die Policy die Seite trotzdem ausführen
und würde dann aber einen kurzen Report in Form von einem JSON an eine von mir definierte URL schicken. Und so habe ich halt die Möglichkeit, auch im laufenden Betrieb erst mal die Policy zu setzen, zu schauen, würde die Seite denn noch funktionieren, kann auch auf Produktion schauen, ob die Seite noch funktioniert und kann das Stück für Stück halt eben an- oder abschalten.
Man findet das zum Beispiel bei Twitter oder bei Disqas. Bei Twitter sieht es dann tatsächlich so aus, die würden zum Beispiel Skripte von connect.face.net erlauben, von doubleclick.net für irgendwelches Ad-Tracking. Man hat die Möglichkeit, auch so etwas zu schreiben wie https://wildcard.
Das heißt, dann würde ich schon mal nur das Nachladen von Ressourcen von https zulassen. Ich kann so etwas wie evil abschalten in meinem Javascript. Und was man auf jeden Fall nicht vergessen sollte, ist am Ende halt die eigene Seite zuzulassen oder eigene Domain, wenn da irgendwo Javascript drin ist.
Das wäre irgendwie ein Beispiel, wie man so einen Announce notiert. Man kann festlegen, wer die Seite einbinden darf, Font-Source, Meteor-Source, das wären jetzt alles Beispiele dafür. Für CSS wird auf Twitter inline.css zum Beispiel zugelassen. Für Skript ist es verboten, das ist das Default-Verhalten,
wenn die Policy an ist. Und am Ende sehen wir dann einfach, wie so eine Report-Jury aussehen kann. Hier rennt der Server dann irgendeine ID rein und dann kann ich das halt über die Access-Logs vom Apache oder so dann auch nochmal referenzieren. Ja. Ja, fast.
Also das Problem ist tatsächlich, wie immer, der Internet-Explorer, der da nicht ganz so weit vorne dabei ist mit Support, aber Chrome und Firefox, unterstützen zumindest mal CSP Level 2. Und im Moment arbeiten die an diesem Level 3-Spec so ein bisschen unterschiedlich von Features.
Aber ich würde mal auch erwarten, dass es zumindest Chrome und Firefox implementiert wird. Das ist ein zusätzliches Feature. Ich soll trotzdem meine Security-Bugs fixen, aber ich habe vielleicht auch nicht immer die Möglichkeit, den Quercode von der Anwendung zu ändern oder zu editieren oder irgendwie ich benutze ein Plugin und da ist halt eben doch irgendwo inline JavaScript dran.
Und damit kann ich es zumindest nochmal ein Stück weit einschränken und einfach als Hatter dazu konfigurieren, ohne dass ich diese Anwendung wirklich anfassen muss. So. Damit wären wir eigentlich am Ende von dem Talk. Wir haben angefangen, eine Beispielweb-Anwendung Clojure zu bauen.
Die ist allerdings noch Work-in-Progress. Wir haben intern so einen Twitter-Klon, der nennt sich Status ist. Haben dann festgestellt, da haben wir versucht, auf Sessions zu verzichten. Das ist dann ein schlechtes Beispiel, um da irgendwie komplexere Identifizierungskonfiguration zu zeigen. Gucken wir mal, wie man damit weiterkommt.
Gibt es denn Fragen? Was ist der Status Quo, das ich da sehe? Es ist so, dass man eher viel selber machen muss.
Das ist einfach so. Weil man, also in Clojure möchte man meistens wissen, was genau unten drunter passiert. Deswegen nicht, dass ich gesehen habe. Sag mal so. Also das ist jetzt das auch, was wir so als Status Quo bisher aus Erfahrungen gefunden haben
und was sich im Netz auch findet. Darüber hinaus gibt es eigentlich nichts. Zumindest nicht, dass wir es wissen. Wenn jemand da irgendwas kennt, freuen wir uns über Hinweise.
Gut, dann vielen Dank.