diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2023-05-31 19:08:55 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2023-05-31 19:08:55 -0700 |
commit | cff43523a86dcfa75bff8b50660ac3e60f798882 (patch) | |
tree | e955bcb5deff7a59626d7815a5e56cfb5a8ae4c3 | |
parent | 1426a6c942b6fdbdb28a78c61f73aab31c7f83c6 (diff) | |
download | tl-who-cff43523a86dcfa75bff8b50660ac3e60f798882.tar.gz tl-who-cff43523a86dcfa75bff8b50660ac3e60f798882.tar.bz2 tl-who-cff43523a86dcfa75bff8b50660ac3e60f798882.zip |
Fix lack of escaping for constant items.
* who.tl (tree-to-template): Recognize string elements
and html-encode them at macro time before adding
to list. Recognize (noesc ...) syntax to defeat this.
Error if it isn't given one argument that is a constant.
* test/simple.tl: New test cases 46 to 49.
* README.md: Document new differences between
CL-WHO and TL-WHO.
-rw-r--r-- | README.md | 21 | ||||
-rw-r--r-- | test/simple.tl | 37 | ||||
-rw-r--r-- | who.tl | 8 |
3 files changed, 64 insertions, 2 deletions
@@ -51,7 +51,7 @@ properties, those are the attributes: ::text (:a :href "foo.html") -> <a href="foo.html"></a> - + (:a :href "foo.html" :target "__blank") -> <a href="foo.html" target="__blank"></a> @@ -165,7 +165,9 @@ Here are the differences to be aware of: "<foo bar='NIL'></foo>" * TL-WHO fixes the issue that CL-WHO doesn't HTML-escape the values of - attributes, and that its local macro `fmt` likewise doesn't escape. + of constant string material, of attributes, and of material added + by local macro `fmt`. + This is a potential security issue, because if an untrusted value is interpolated, it can be a vector for an injection attack. The special variable `*cl-who-compat*` can be set true to disable the @@ -178,12 +180,27 @@ Here are the differences to be aware of: (:a :href "https://example.com'>malicious here</a><a href='blah" "click me")) "<a href='https://example.com'>malicious here</a><a href='blah'>click me</a>" + Not escaping constant material is error-prone. + The CL-WHO user has to remember to write (:div "black&white") + whereas the TL-WHO user just writes (:div "black&white"); the & + escape is produced by TL-WHO. + * TL-WHO provides a `noesc` syntax. When the value of an attribute is expressed as `(noesc <expr>)`, escaping is disabled: ::text (:a :href (noesc trusted-url) "click me") + A more limited form of `noesc` can be used in tag bodies, + to defeat the default escaping applied to constant material. + + The following: + + ::text + (:div (noesc "&") " <") + + produces `<div>& &lt;</div>`. + * TL-WHO provides a `noesc-fmt` which doesn't HTML-escape. * TL-WHO provides `escq` and `escj` local macros. `escq` is like `esc` diff --git a/test/simple.tl b/test/simple.tl index 4dc5b88..6f9464d 100644 --- a/test/simple.tl +++ b/test/simple.tl @@ -487,3 +487,40 @@ (:div :span (fmt "~a&" 42) :color (escj "</script>"))) "<div span='42&' color='<\\/script>'></div>") + +;;; 46 +;;; Test that literal material is being escaped +(test (with-html-output-to-string (out) + (:div :attr "&" "this & that")) + "<div attr='&'>this & that</div>") + +;;; 47 +;;; Test for issues in JS <script> escaping. +(test (with-html-output-to-string (out) + (:script + "var x = a< // </script>\n" + "var nl = \"" (escj "\n") "\";\n")) + "<script>var x = a&lt; // </script>\n \ + var nl = \"\\n\";\n \ + </script>") + +;;; 48 +;;; Test noesc syntax in tag body. +(test (with-html-output-to-string (out) + (:div + (noesc "&"))) + "<div>&</div>") + +;;; 49 +;;; Test noesc with wrong arguments or nonconstant argument +(test (catch + (each ((syntax '((noesc "&" "<") + (noesc) + (noesc *stdout*)))) + (eval ^(with-html-output-to-string (out) + (:div + ,syntax)))) + (error (x) (if (and (contains "noesc" x) + (contains "requires" x)) + :good))) + :good) @@ -188,9 +188,17 @@ ((@(keywordp) .@nil) . @nil)) ;; the syntax for a tag - process it (ncon [process-tag element tree-to-template])) + ((noesc @(constantp @item)) + ;; (noesc ...) syntax on constant + (add item)) + ((noesc . @nil) + (compile-error tree "noesc requires single constant argument")) (@(consp) ;; list - insert as sexp (add ^(expander-let ((*indent* , *indent*)) ,element))) + (@(stringp) + ;; string - insert escaped version + (add (html-encode* element))) ;; something else - insert verbatim (@else (add else)))))) |