chrisfrank / rack-component Goto Github PK
View Code? Open in Web Editor NEWHandle HTTP requests with modular, React-style components, in any Rack app
Handle HTTP requests with modular, React-style components, in any Rack app
Because Rack::Component uses raw Ruby string interpolation -- Hello, #{env[:world]}
-- there's not an obvious way to escape output by default. This leaves components open to XSS attacks like this:
evil_user = { name: 'Mirror Spock <script src="https://evil.script.js" />' }
class UserProfile < Rack::Component
render do |env|
"<h1>#{env[:name]}</h1>"
end
end
UserProfile.call(evil_user) #=> <h1>Mirror Spock <script src="https://evil.script.js" /></h1>
Anyone visiting Spock's profile would unknowingly load the evil script.
Adding an instance method that escapes untrusted input, let's call it #h
, would be trivial:
class UserProfile < Rack::Component
render do |env|
"<h1>#{h env[:name]}</h1>"
end
end
UserProfile.call(evil_user) #=> <h1>Mirror Spock <script src="https://evil.script.js" /></h1>
# no problem
This approach would be an improvement, but still not very secure. We'd have to remember to call h
every time we render untrusted input.
env
automaticallyIn addition to adding an h
method, we could change how the #env
accessor works and escape its values by default. This would make anything in env
safe by default, which is good, but it wouldn't apply to variables outside of env.
Under this approach, this component would safely print a user's name:
class UserProfile < Rack::Component
render do |env|
"<h1>#{env[:name]}</h1>"
end
end
UserProfile.call(evil_user) #=> <h1>Mirror Spock <script src="https://evil.script.js" /></h1>
But this component would print the malicious script:
class EvilUserProfile < Rack::Component
render do |env|
user = FakeUserModel.find(id_of_evil_user)
"<h1>#{user[:name]}</h1>"
end
end
UserProfile.call(evil_user) #=> <h1>Mirror Spock <script src="https://evil.script.js" /></h1>
Instead of interpolating with #{}
, we could interpolate with %{}
, passing the output to Kernel#format
under the hood. See this Idiosyncratic Ruby article for reference, and the code in the the "escape" branch for an implementation-in-progress.
This approach seems promising to me, but there are some decisions to make about the scope in which to evaluate template tokens. Here are a few possibilities:
# We could interpret tokens in the context of the component instance:
class UserProfile < Rack::Component
render do
"<h1>%{env[:name]}</h1>"
end
end
# We could interpret tokens as keys in `env`:
class UserProfile < Rack::Component
render do
"<h1>%{name}</h1>"
end
end
Either way, under the hood, we would escape all strings by default. To render non-escaped strings, you'd just use #{}
instead of %{}
.
Under this approach, I worry that mixing #{}
and %{}
is confusing, and there would definitely be times when #{}
is required, like to render a list:
class List < Rack::Component
render do
<<~HTML
<ul>
#{env[:posts].map { |post| ListItem.call(post) }.join}
</ul>
HTML
end
class ListItem < Rack::Component
render { "<li>%{env[:title]}</li>" }
end
end
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.