2021-04-08 14:24:59 +03:00
..
2021-04-05 00:08:28 +03:00
2021-04-05 00:08:28 +03:00
2021-04-08 14:24:59 +03:00
2021-04-05 00:08:28 +03:00

7-template


Dream templates allow interleaving OCaml and HTML in a pretty straightforward way, and help with XSS protection. After looking at the correct example, we will weaken and then exploit it.

let render param =
  <html>
    <body>
      <h1>The URL parameter was <%s param %>!</h1>
    </body>
  </html>

let () =
  Dream.run
  @@ Dream.logger
  @@ Dream.router [

    Dream.get "/:word"
      (fun request ->
        Dream.param "word" request
        |> render
        |> Dream.respond);

  ]
  @@ Dream.not_found
$ dune exec --root . ./template.exe

This requires a bit more setup in our dune file to run the template preprocessor:

(executable
 (name template)
 (libraries dream)
 (preprocess (pps lwt_ppx)))

(rule
 (targets template.ml)
 (deps template.eml.ml)
 (action (run dream_eml %{deps} --workspace %{workspace_root})))

The substitution, <%s param %>, uses Printf conversion specifications from the standard library. So, you can do things like this:

  • <%i my_int %> to print an OCaml int.
  • <%02x my_hex_int %> to print an int in hexadecimal, with at least two characters, left-padded with zeroes.

Security

The template automatically passes strings through Dream.html_escape before inserting them into the output. This only applies to formats that can emit dangerous characters: %s, %S, %c, %C, %a, and %t.

You can suppress the hidden call to Dream.html_escape using !; for example, <%s! param %>. You may want to do this if your data is already escaped, or if it is safe for some other reason. But be careful!


To show the danger, let's launch a script injection (XSS) attack against this tiny Web app! First, go to template.eml.ml, change the substitution to <%s! param %>, and restart the app. Then, visit this highly questionable URL:

http://localhost:8080/%3Cscript%3Ealert(%22Impossible!%22)%3C%2Fscript%3E

This URL will cause our Web app to display an alert box, which we, as the developers, did not intend!

XSS example

Despite all the URL-escapes, you may be able to see that the URL contains a complete <script> tag that runs a potentially arbitrary script. Our app happily pastes that script tag into HTML, causing the script to be executed by our clients!

If you change the substitution back to <%s param %>, and visit that same URL, you will see that the app safely formats the script tag as text:

XSS prevented


In general, if you are not using the templater, you should pass any text that will be included in HTML through Dream.html_escape, unless you can guarantee that it does not contain the characters <, >, &, ", or '. Also, always use quoted attribute values — the rules for escaping unquoted attributes are much more invasive.

Likewise, escaping inline scripts and CSS is also more complicated, and not supported by Dream.



Next steps:

  • 8-debug shows how to turn on debug responses, and get more info about errors.
  • 9-error sets up a central error template for all errors.

Up to the tutorial index