Prevent some possible XSS attacks where user input makes its way into JSON and contains </script> tags.

This commit is contained in:
Andrew Cantino 2013-09-07 00:34:51 -07:00
parent 2ee05ab77c
commit 3eaa9272b1
6 changed files with 44 additions and 10 deletions

View file

@ -17,9 +17,9 @@
<script>
$(function() {
var $chart = $(".chart-container.group-<%= index.to_s %>").last();
var data = <%= data.map {|count, time| { :x => time.to_i, :y => count.to_i } }.to_json.html_safe %>;
var peaks = <%= ((@agent.memory[:peaks] && @agent.memory[:peaks][group_name]) || []).to_json.html_safe %>;
var name = <%= group_name.to_json.html_safe %>;
var data = <%= Utils.jsonify(data.map {|count, time| { :x => time.to_i, :y => count.to_i } }) %>;
var peaks = <%= Utils.jsonify((@agent.memory[:peaks] && @agent.memory[:peaks][group_name]) || []) %>;
var name = <%= Utils.jsonify(group_name) %>;
renderGraph($chart, data, peaks, name);
});

View file

@ -35,8 +35,8 @@
<script>
$(function() {
var $chart = $(".chart-container.group-<%= index.to_s %>").last();
var data = <%= group.select {|e| e.payload[:count].present? }.sort_by {|e| e.payload[:time] }.map {|e| { :x => e.payload[:time].to_i, :y => e.payload[:count].to_i } }.to_json.html_safe %>;
var name = <%= filter.to_json.html_safe %>;
var data = <%= Utils.jsonify(group.select {|e| e.payload[:count].present? }.sort_by {|e| e.payload[:time] }.map {|e| { :x => e.payload[:time].to_i, :y => e.payload[:count].to_i } }) %>;
var name = <%= Utils.jsonify(filter) %>;
renderGraph($chart, data, [], name);
});

View file

@ -132,12 +132,12 @@
<p>
<b>Options:</b>
<pre><%= JSON.pretty_generate @agent.options || {} %></pre>
<pre><%= Utils.pretty_jsonify @agent.options || {} %></pre>
</p>
<p>
<b>Memory:</b>
<pre><%= JSON.pretty_generate @agent.memory || {} %></pre>
<pre><%= Utils.pretty_jsonify @agent.memory || {} %></pre>
</p>
</div>
</div>

View file

@ -7,7 +7,7 @@
<p>
<b>Payload:</b>
<pre><%= JSON.pretty_generate @event.payload || {} %></pre>
<pre><%= Utils.pretty_jsonify @event.payload || {} %></pre>
</p>
<% if @event.lat && @event.lng %>

View file

@ -52,7 +52,19 @@ module Utils
end
end
def self.jsonify(thing)
thing.to_json.gsub('</', '<\/').html_safe
# Output JSON that is ready for inclusion into HTML. If you simply use to_json on an object, the
# presence of </script> in the valid JSON can break the page and allow XSS attacks.
# Optionally, pass `:skip_safe => true` to not call html_safe on the output.
def self.jsonify(thing, options = {})
json = thing.to_json.gsub('</', '<\/')
if !options[:skip_safe]
json.html_safe
else
json
end
end
def self.pretty_jsonify(thing)
JSON.pretty_generate(thing).gsub('</', '<\/')
end
end

View file

@ -55,4 +55,26 @@ describe Utils do
Utils.values_at({ :foo => { :bar => "escape this!?" }}, "escape $.foo.bar").should == ["escape+this%21%3F"]
end
end
describe "#jsonify" do
it "escapes </script> tags in the output JSON" do
cleaned_json = Utils.jsonify(:foo => "bar", :xss => "</script><script>alert('oh no!')</script>")
cleaned_json.should_not include("</script>")
cleaned_json.should include("<\\/script>")
end
it "html_safes the output unless :skip_safe is passed in" do
Utils.jsonify({:foo => "bar"}).should be_html_safe
Utils.jsonify({:foo => "bar"}, :skip_safe => false).should be_html_safe
Utils.jsonify({:foo => "bar"}, :skip_safe => true).should_not be_html_safe
end
end
describe "#pretty_jsonify" do
it "escapes </script> tags in the output JSON" do
cleaned_json = Utils.pretty_jsonify(:foo => "bar", :xss => "</script><script>alert('oh no!')</script>")
cleaned_json.should_not include("</script>")
cleaned_json.should include("<\\/script>")
end
end
end