On Feb 5, 2013, at 9:13 AM, Paul Stadig wrote:
> On Tue, Feb 5, 2013 at 8:07 AM, Rich Hickey <
richh...@gmail.com> wrote:
>> While #= is undocumented, it is not unused, and dramatically altering it would be a significant breaking change for many.
>
> I would like to see more data on this point. I ran the Sonian tests
> against Chas' patch which defaults to turning off *read-eval* and
> there were minimal changes necessary. We have 22k lines of source and
> 20k lines of tests, and it requires adding 5 binding forms around the
> places we are reading data. These sites are easy to find as well.
First, if you have to change your code, it's a breaking change. We don't have any breaking changes in 1.5 otherwise.
Second, while it might be 'easy' to find these sites, more nefarious are those cases where:
Programmer A goes and finds his sites that need read eval, establishes the binding.
Programmer B rests easy knowing his code that needs to be safe is safe with the defaults, does nothing.
C) Except - some of programmer B's calls are nested, or worse, later become nested, in Programmer A's eval contexts.
The more people need to do A, the more likely we'll see C.
A key point of this middle-ground default is that people will rarely if ever need to bind *read-eval* to true. That doesn't, and can't, eliminate the need for B to specify safety, but dramatically reduces the possibility of C. It also means that more experienced programmers can using binding *read-eval* false to establish even wider safe contexts than safe-read can supply, knowing e.g. read-oriented libraries are unlikely to establish bindings of their own.
> You
> just search for places where you call read-*. It seems to me it would
> be a minimal effort for an important security fix.
>
Iff you were getting an important security fix by changing the default - but you aren't:
>> Most important - ***as long as read-eval behavior is governed by a dynamic binding***, no one should ever rely upon the safety of the default binding (however we set it), since a surrounding context might have altered it. Thus - if you want a safe read on a particular source YOU must EXPLICITLY ensure it for that call.
>
> This is important advice and should be taken to heart.
It's not a matter of taking to heart. If true, the only route to safe programs is explicit safe-read when untrusted source.
> You are right
> that even with safe defaults one should be prudent and explicitly bind
> *read-eval* to false. However, this whole issue is about safe
> defaults.
>
No, it's not. It's about safe programs, which in this case will not fall out of 'safe' defaults. This entire discussion has been poisoned by presuming, and focusing on, an answer, rather than the problem.
>> The *read-whitelist* provides additional control short of granting full eval
>
> The default value for *read-eval* + *read-whitelist* still grants full eval.
>
> user=> *read-eval*
> :default
> user=> (read-string "#=(clojure.core$eval/applyToHelper #=(var
> clojure.core/eval) ((println \"pwned\")))")
> pwned
> nil
>
Fixed in beta8 - thanks for the report.
> The default for *read-eval* is still unsafe, but now the situation
> around read-*, safe-read-*, load, and *read-eval* is more complicated,
> which I think is worse for inexperienced Clojure developers.
Dynamic binding is complex. safe-read is not.
>
> There may be edge cases for reading in records, but people can bind
> *read-eval* to true in those.
I contest your presumption that a world in which binding *read-eval* true is easy, necessary and common, combined with inexperienced programmers not understanding binding and lulled into a sense of security due to the 'safe default', thereby failing to be explicitly safe, is a safer world. Defaults that can be made to lie are the absolute worst.
I encourage you all, as thought leaders in the Clojure community, to actually address the problem - unsafe reading, with a solution that actually addresses it - explicit safe reading, and to engage in the education and documentation effort.
Rich