Slide 1

Slide 1 text

Simple AND Secure? EuroClojure 2017 Joy Clark

Slide 2

Slide 2 text

Caution: Code on Slides Oscar Sutton

Slide 3

Slide 3 text

Simplicity Imani Clovis

Slide 4

Slide 4 text

Clojure Ring Java HTTP Server Ring Server Adapter request response fn request response https://github.com/ring-clojure/ring/blob/master/SPEC

Slide 5

Slide 5 text

Ring Requests & Responses (def request {:uri "/" :request-method :get :headers {"Accept" "text/plain"}}) (defn example-app [req] {:status 200 :body (str "Hello " (:uri req) "!")}) (ring.adapter.jetty/run-jetty example-app {:port 4000}) webapp Java HTTP Server Ring Server Adapter

Slide 6

Slide 6 text

Ring Middleware modi ed request (i.e. added session info) modi ed response (i.e. added headers) request response middleware modi ed request modi ed response response modi ed request response request condition? true false (defn middleware [handler] (fn [request] ;; Modify request before sending it to the web app (let [response (handler request)] ;; modify response before returning it to the user response)))

Slide 7

Slide 7 text

Routing with Compojure routing fn route 1 route 2 route 3 not-found request response (defroutes app-routes (GET "/" request (list-users request)) (POST "/" {params :params :as request} (add-user request params)) (GET "/:username" [username :as request] (get-user request username)) (PUT "/:username" [username email password :as request] (update-user request username email password)) (DELETE "/:username" [username] (delete-user username)))

Slide 8

Slide 8 text

Putting it all together (def webapp (-> app-routes auth-middleware (wrap-defaults secure-site-defaults))) (ring.adapter.jetty/run-jetty webapp {:port 4000}) auth? handle no auth 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

Slide 9

Slide 9 text

Where is the security? Scott Webb

Slide 10

Slide 10 text

Security ≠ Magical Frameworks (public-domain Vasnetsov - belygorod.ru)

Slide 11

Slide 11 text

Where is the security? auth? handle no auth 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

Slide 12

Slide 12 text

We have to add the last piece! Hans‑Peter Gauster

Slide 13

Slide 13 text

Security = Teamwork + Review (cc-by Kevin Dooley - flic.kr/p/dxCnzT)

Slide 14

Slide 14 text

How to Write a Secure Web Application Maintain your application Stay informed! Register for Security Advisories KISS Know what you are doing Monitor your Application

Slide 15

Slide 15 text

OWASP Top 10 2017 Injection Broken Authentication / Session Management XSS Broken Access Control Security Misconfigurations Sensitive Data Exposure Insufficient Attack Protection Cross Site Request Forgery Using Components with Known Vulnerabilities Underprotected APIs

Slide 16

Slide 16 text

HTTPS Just a friendly reminder to use SSL! (def options {:port 3000 :join? false :ssl? true :ssl-port 4000 :keystore "ssl/keystore" :key-password "somesecret" :host "example.com"}) (ring.adapter.jetty/run-jetty webapp options)

Slide 17

Slide 17 text

XSS - Cross-site Scripting

Slide 18

Slide 18 text

XSS - Cross-site Scripting (defn error-login [username] (str "
Hi " username "! Please try logging in again!
")) (error-login "alert('Evil XSS!');") > "
Hi alert('Evil XSS!');! Please try logging in again!
"

Slide 19

Slide 19 text

Validate Input - Escape Output Ensure that the user's input is what you expect. Libraries: clojure.spec Bouncer

Slide 20

Slide 20 text

Validate Input - Escape Output (selmer.parser/render "Hello {{name}}!" {:name "alert('hi!');"}) > "Hello <script>alert('hi!');</script>!"

Slide 21

Slide 21 text

Validate Input - Escape Output Templating Language Escaping by default? # GitHub References Last Updated >2.0.0-alpha1 19481 15 Jan 2017 Yes 7412 21 Sep 2015 Yes 6465 28 Jun 2017 Yes 1177 17 Jun 2017 hiccup enlive Selmer hoplon Statistics taken on 17 July 2017

Slide 22

Slide 22 text

CSRF - Cross-site Request Forgery

Slide 23

Slide 23 text

Protect Against CSRF Don't use GET requests to change state! SameSite=Strict cookie attribute Ring-Anti-Forgery

Slide 24

Slide 24 text

CSRF Protection

Slide 25

Slide 25 text

ring.middleware.anti-forgery (require '[ring.middleware.anti-forgery :refer [*anti-forgery-token*]]) (selmer.parser/render-file "index.html" {:antiforgery *anti-forgery-token*}) index.html: ...

Slide 26

Slide 26 text

Injection (defn query-user [username] (sql/query db-conn [(str "SELECT * FROM Users WHERE Username = '" username "';")])) (query-user "fred' or 'a'='a")

Slide 27

Slide 27 text

Parameterize Queries db/users.sql: -- name: get-user SELECT * FROM Users WHERE Username = :username ; (yesql.core/defqueries "db/users.sql" {:connection db-conn}) (get-user {:username "fred"}) > {:username "fred" :email "mr.froggy@quackers.com" :userid 4 :password "...some bycrypt hash..."}

Slide 28

Slide 28 text

Authentication & Authorization How do I know if the user is who he says he is? How do I know if the user is allowed to access a resource?

Slide 29

Slide 29 text

Introducing Buddy

Slide 30

Slide 30 text

Buddy-Auth Ring Middleware Integration Authentication information saved in :identity in the request map Different Backends: HTTP Basic, Session, Token, Signed JWT, Encrypted JWT Possibility to implement custom authentication backend

Slide 31

Slide 31 text

Simple Auth Example (require '[buddy.auth.backends :as backends]) (defn ldap-auth [request auth] (let [username (:username auth) password (:password auth)] ; do magic ldap authentiation ; return logical true username)) (def backend (backends/basic {:realm "myAPI" :authfn ldap-auth}))

Slide 32

Slide 32 text

Authorization with Buddy (def access-rules [{:uris ["/users" "/users/:username"] :handler buddy.auth/authenticated? :request-method :get} {:uris ["/users/:username" "/users/:username/edit"] :handler is-user?}]) (defn is-user? [request] (when-let [user (:identity request)] (= user (get-in request [:match-params :username]))))

Slide 33

Slide 33 text

Auth Middleware (defn error-redirect [request _value] (redirect-to-login (request-url request))) (defn auth-middleware [handler] (let [backend (auth-backend secret)] (-> handler (wrap-access-rules {:rules access-rules :on-error error-redirect}) (wrap-authentication backend))))

Slide 34

Slide 34 text

Protect Your APIs! Rita Morais

Slide 35

Slide 35 text

HTTP Security Headers (def middleware-settings {:session {:cookie-attrs {:http-only true :secure true :same-site :strict}} ;; not default :security {:anti-forgery true :xss-protection {:enable? true, :mode :block} :frame-options :sameorigin :content-type-options :nosniff :ssl-redirect true :hsts true}}) "api-defaults", "site-defaults", "secure-site- defaults", ...

Slide 36

Slide 36 text

In Summary... Use HTTPS! Validate user input and escape output Templating library with automatic HTML escaping!!! Use site-defaults or secure-site- defaults for for authentication and authorization ring defaults Buddy

Slide 37

Slide 37 text

Example Web Application: (WIP) https://github.com/innoq/quackers Joy Clark joy.clark@innoq.com @iamjoyclark