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 OCamlint.<%02x my_hex_int %>to print anintin 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!
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.
Likewise, escaping inline scripts and CSS is also more complicated, and not supported by Dream.
Next steps:
8-debugshows how to turn on debug responses, and get more info about errors.9-errorsets up a central error template for all errors.

