Reads the next object from stream, which must be an instance of
java.io.PushbackReader
or some derivee. Stream defaults to the current value of*in*
.
(read)
(read stream)
(read stream eof-error? eof-value)
(read stream eof-error? eof-value recursive?)
user=> (read)
( + 1 1 ) ; <= User types this
(+ 1 1)
user=> (eval (read))
(+ 1 1) ; <= User types this
2
clojure.core/read
or clojure.core/read-string
to read data from untrusted sources.
They were designed only for reading Clojure code and data from trusted sources (e.g. files that you know you wrote yourself, and no one else has permission to modify them).
Instead, either:
- Use another data serialization format such as JSON, XML, etc. and a library for reading them that you trust not to have vulnerabilities, or
- if you want a serialization format that can be read safely and looks like Clojure data structures, use edn.
For Clojure 1.3 and later, the tools.reader
contrib library provides an edn reader. There is also clojure.edn/read
and clojure.edn/read-string
provided in Clojure 1.5.
*read-eval*
has its default value of true, because an attacker could cause your application to execute arbitrary code while it is reading.
Example:
(read-string "#=(clojure.java.shell/sh \"echo\" \"hi\")")
;=> {:exit 0, :out "hi\n", :err ""}
It is straightforward to modify the example above into more destructive ones that remove all of your files, copy them to someone else's computer over the Internet, install Trojans, etc.
Even if you do bind *read-eval*
to false first, like so:
(defn read-string-unsafely [s]
(binding [*read-eval* false]
(read-string s)))
You may hope you are safe reading untrusted data that way, but in Clojure 1.4 and earlier, an attacker can send data that causes your system to execute arbitrary Java constructors. Most of these are benign, but it only takes one to ruin your application's day. Examples that should scare you:
This causes a socket to be opened, as long as the JVM sandboxing allows it:
(read-string-unsafely "#java.net.Socket[\"www.google.com\" 80]")
This causes precious-file.txt
to be created if it doesn't exist, or if it does exist, its contents will be erased (given appropriate JVM sandboxing permissions, and underlying OS file permissions).
(read-string-unsafely "#java.io.FileWriter[\"precious-file.txt\"]")
The particular issue of executing arbitrary Java constructors used in the examples above no longer works in Clojure 1.5 when read-eval is false. Even so, you SHOULD NEVER USE clojure.core/read or clojure.core/read-string for reading untrusted data. Use an edn reader or a different data serialization format.
Why should I do this, you may ask, if Clojure 1.5 closes the Java constructor hole? Because clojure.core/read
and read-string
are designed to be able to do dangerous things, and they are not documented nor promised to be safe from unwanted side effects. If you use them for reading untrusted data, and a dangerous side effect is found in the future, you will be told that you are using the wrong tool for the job. The clojure.edn/read
and read-string
, and
the tools.reader.edn
library, are documented to be safe from unwanted side effects, and if any bug is found in this area it
should get quick attention and corrected. If you understand all of the above, and want to use read or
read-string to read data from a trusted source, continue on below.
The function
read
wants its reader arg (or*in*
) to be ajava.io.PushbackReader
.
with-open
closes r
after the with-open
body is done.
*read-eval*
specifies whether to allow #=() forms when reading, and evaluate them as a side effect while reading.
(defn read-from-file-with-trusted-contents [filename]
(with-open [r (java.io.PushbackReader.
(clojure.java.io/reader filename))]
(binding [*read-eval* false]
(read r))))
;=> (spit "testfile.txt" "{:a 1 :b 2 :c 3}") nil
(read-from-file-with-trusted-contents "testfile.txt")
;=> {:a 1, :b 2, :c 3}