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

6-template


Dream templates allow interleaving OCaml and HTML in a pretty straightforward way, and help with XSS prevention:

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 of setup in our dune file to run the template preprocessor:

(executable
 (name template)
 (libraries dream))

(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, go to this URL:

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

This cryptic and highly questionable URL will cause our web app to display an alert box, which we, as the developers, did not intend! 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.


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.



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