How to safely embed JSON with </script> in HTML document? - ruby-on-rails

In a Rails 3.1 app, how can I safely embed some JSON data into an HTML document?
Suppose I have this in a controller action:
#tags = [
{name:"tag1", color:"green"},
{name:"</script><b>I can do something bad here</b>", color:"red"}
]
And this in a corresponding view:
<script type="text/javascript" charset="utf-8">
//<![CDATA[
var tags_list = <%= #tags.to_json %>;
// ]]>
</script>
Then I get this in resulting HTML:
var tags_list = [
{"name":"tag1","color":"green"},
{"name":"</script><b>I can do something bad here</b>","color":"red"}
];
which triggers a SyntaxError: Unexpected token & in Chrome
If I remove the Rails' default HTML escaping with <%=raw tags.to_json
%>, then it returns this:
var tags_list = [
{"name":"tag1","color":"green"},
{"name":"</script><b>I can do something bad here</b>","color":"red"}
];
which, of course, breaks the HTML document with </script>.
Can I somehow tell to_json() method to return something more like this:
var tags_list = [
{"name":"tag1","color":"green"},
{"name":"</script><b>I can do something bad here</b>","color":"red"}
];
I asked this question on rubyonrails-talk mailing list, and I understand now that some people think that's a very bad idea to begin with, but in my case it works very nicely, as long as there are no HTML special chars in the data. So I just want to make the string returned by to_json HTML safe and still have JavaScript parse it properly.
UPDATE:
Based on #coreyward comment, I did make it a JS string literal, and that seems to be working great now. Its not quite as elegant of a solution as I was hoping for, but its not too bad either. Here is the code that is working for me:
<% tags = [{name:"tag1", color:"green"}, {name:"</script><b>I can \n\ndo something bad here</b>", color:"red"}] %>
<script type="text/javascript" charset="utf-8">
//<![CDATA[
var tags_list = $.parseJSON('<%=j tags.to_json.html_safe %>');
// ]]>
</script>
which results in:
<script type="text/javascript" charset="utf-8">
//<![CDATA[
var tags_list = $.parseJSON('[{\"name\":\"tag1\",\"color\":\"green\"},{\"name\":\"<\/script><b>I can \\n\\ndo something bad here<\/b>\",\"color\":\"red\"}]');
// ]]>
</script>

Your code using just #tags.to_json works in rails3, if you enable it with:
ActiveSupport.escape_html_entities_in_json = true
Otherwise, your other option is this:
var tags_list = <%= raw #tags.to_json.gsub("</", "<\\/") %>;
This saves the client having to parse the whole thing through $

The proper way in 2019 is to wrap obj.to_json with json_escape function. json_escape is directly intended for escaping specific HTML symbols inside JSON strings. Example below from the documentation:
json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
# => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"
json_escape(json)
# => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"
JSON.parse(json) == JSON.parse(json_escape(json))
# => true
It seems this page appears on top of Google Search results, that's why I decided to provide a comment with an update :)

btw, this works but is not a good solution in my opinion:
<script type="text/javascript" charset="utf-8">
//<![CDATA[
var tags_list = <%=raw #tags.to_json.gsub('/', '\/') %>;
// ]]>
</script>

I think that if you try this it will work:
var tags_list = "<%== #tags.to_json.gsub('/', '\/') %>";
(Notice the double == and the " ")

For instance with this in app/layouts/application.html.slim:
javascript:
window.translations = #{raw t("js").to_json};
And this in the translations:
js:
name:
must_be_present: Must be present<script>alert(1)</script>
The result will be escaped:
<script>window.translations = {"name":{"must_be_present":"Must be present\u003cscript\u003ealert(1)\u003c/script\u003e"}};</script>

Related

Rails - How to only escape <script> tag

In Rails, I see
+ html_escape: escape all tags.
+ sanitize: remove all tags what isn't in whilelist.
Now, I want only escape script tag, not escapse other tags.
Do you have a solution ? Thanks all!
As you are on rails 4.2.5, you can use https://github.com/rails/rails-html-sanitizer which gets installed with rails. You can do following to escape only script tag.
scrubber = Rails::Html::TargetScrubber.new
scrubber.tags = ['script']
html_fragment = Loofah.fragment('<script></script><div></div>')
html_fragment.scrub!(scrubber)
html_fragment.to_s # outputs "<div></div>"
string = '<html> <title> <head> <script type="javascript"></script> </head> </title> </html>'
string.gsub(/<script.*[\s\S]*\/script>/,"")
=> "<html> <title> <head> </head> </title> </html>"
Update
If you are using Rails 4.2.5 you may need this.
Rails::HTML::TargetScrubber
Rails providing so many options for string / HTML entities
s = "<script>alert('Hello');</script>"
option : WhiteListSanitizer
white_list_sanitizer = Rails::Html::WhiteListSanitizer.new
white_list_sanitizer.sanitize(s, tags: %w())
white_list_sanitizer.sanitize(s, tags: %w(table tr td), attributes: %w(id class style))
=> "alert('Hello');"
Refer this link alse
How to show some HTML entities on title tag using Rails
string.gsub!(/<(?=script)||(?<=script)>/) {|x| "#\{x}"}

Best way to include javascript in Rails via content_for

I have some pages in my Rails application that need one off bits of javascript to be included, ideally just before the </body> tag. There is no real need to have this javascript included on EVERY page since most don't use it. I've found a way to make this work, but I think the code is terrible.
How would you do the same thing or how would you refactor the existing code?
View simplified, sample code on gist.github.com:
https://gist.github.com/scottswezey/ffc7bf52041b976b710a
(Or see the same code below:)
application.html.erb (Layout):
<!DOCTYPE html>
<html lang="en">
<head>
...
</head>
<body>
...
<script>
$(function() {
<%= yield(:js) %>
});
</script>
</body>
</html>
some_view_file.html.erb (View):
<%
str = <<END_OF_STRING
$('.modal').modal()
END_OF_STRING
content_for :js do
str.html_safe
end
%>
Don't ever do it this way: JavaScript doesn't belong in HTML. Just put an appropriate <script> tag in the page, referring to an external JS file, something like this:
application.html.haml
!!!
%html
%head
= yield :javascript
%body
= yield
view file
- content_for :javascript do
= javascript_include_tag 'modal'
app/assets/modal.js
$(document).ready(function() {
$('.modal').modal();
}
This keeps everything nicely separated.
Is it possible to add a .js.erb partial with your JS and render it under the body?
edit: Check out this answer: https://stackoverflow.com/a/10113547/1283742

How do I make an infowindow automatically display as open with Google-Maps-for-Rails

I want to display a map with the infowindow box automatically displayed for the single marker on the page, much like http://code.google.com/apis/maps/documentation/javascript/examples/map-coordinates.html
I've tried to code a callback function to accomplish this, but it's just not working for me.
<% content_for :scripts do %>
<script type="text/javascript" charset="utf-8">
Gmaps.map.callback = function() {
if (Gmaps.map.markers.length == 1) {
var marker = Gmaps.map.markers[0];
var infowindow = marker.infowindow;
infowindow.open(Gmaps.map, marker);
}
}
</script>
<% end %>
Your code is almost perfect. Except that instead of:
 infowindow.open(Gmaps.map, marker);
You should have:
infowindow.open(Gmaps.map.map, marker);
Indeed, Gmaps.map is a container, Gmap.map.map is the google object.
I know these names are confusing. Sorry.
PS: be sure to put this code under the gmaps call in your view.
I am trying to accomplish the same thing, except to just open the first marker out of a list of markers. So the code is almost the same. I've done what you suggested but it's not showing the info window.
<%= gmaps4rails(#json) %>
<% content_for :scripts do %>
<script type="text/javascript" charset="utf-8">
Gmaps.map.callback = function() {
var marker = Gmaps.map.markers[0];
var infowindow = marker.infowindow;
infowindow.open(Gmaps.map.map, marker);
}
</script>
<% end %>
The map display find but the info window doesn't pop up upon initialisation as expected! Any ideas?
Will
The callback function that worked for me:
Gmaps.map.callback = function() {
function openInfoWindow(){
var m, marker;
marker = Gmaps.map.markers[2];
m = marker.serviceObject;
marker.infowindow.open(Gmaps.map.map, m);
}
openInfoWindow();
}
You are mixing Javascript and Ruby together. Take a look at your javascript debugger (you are using one right? If not, the web inspector in Chrome or safari is great, as is Firebug for Firefox) and you'll see it complaining.
Without seeing your controller code I can't give you too many specifics, but take a look at this post and it might point you in the right direction.

rails to_json.html_safe Uncaught SyntaxError: Unexpected identifier

I have in my stock rails 3.1 app's projects#index.html.erb a javascript section to reads like this:
<script type="text/javascript" charset="utf-8">
var projects = <%= #projects.to_json.html_safe -%>
$(function () {
// some other code...
});
</script>
However, Chrome's console complains that "Uncaught SyntaxError: Unexpected identifier"
now, if I remove anything that follows the "var projects" line like this
<script type="text/javascript" charset="utf-8">
var projects = <%= #projects.to_json.html_safe -%>
</script>
everything is fine and when one typed "projects" in the Chrome javascript console, I do get the list of objects
[ object, object, object, ..., object ]
I cannot work out what the issue is here, can you help?
Thanks!
try adding a ; semicolon at the end of statement

how to access javascript variable in rails view

Is there any way to access javasript variable inside the rails view.
I just set some value of javascript variable and want to access it in rails view.
Thanks
You have to understand that ruby code in your views gets executed on the server - before any javascript on the page gets a change to be executed.
That's why you cannot do stuff like this:
<script>
var js_var = 1;
</script>
<%= get_value_of_js_var_somehow %>
The other way round it works:
<script>
var js_var = <% generate_value_with_ruby %>;
do_something_in_javascript_with_js_var();
</script>
You can pass a javascript variable to rails using AJAX. For example if you want to pass the id for an user to a method in a rails controller from javascript you can execute the following code:
<script>
var id = 1;
<%= remote_function :url => {:controller=>'controller_name', :action=>'method_name'}, :with => "'user_id=' + id" %>
</script>
You will receive the variable through a POST request, as a parameter. You can access it using params[:user_id].
def method_name
if params[:user_id].exists?
u = User.where('id = ?', params[:user_id]).first
end
puts u.path
end
Hope I've answered your question.
If you have this Javascript variable in a higher piece of javascript (per se: the application.js), then you can always just reference it in the view.
#application.js
var someVar = "Hello World";
Then in your view (executed on the client), you could to...
<script type='text/javascript'>
alert(someVar);
</script>
I think we need more specific ellaboration if one of these three posts doesn't answer your question.
Suppose we are having script as follows
<script type="text/javascript">
var a="some value";
document.getElementById('tagid').innerHTML='<%= tag(:div,content_tag(:p,' " +a+ " '), :id=>' " +a+ " ', name=>"somename") %>';
</script>

Resources