tag inside javascript", "text": "<p>I'm using backbone, and the general way for passing the collections when the page load is</p>\n\n<pre class="prettyprint"><code>window.router = new Routers.ManageRouter({store: #{@store.to_json});\n</code></pre>\n\n<p>which is fine and works well, until someone decides to add the text "<code>&lt;script&gt;alert("owned")&lt;/script&gt;</code>" to one of the store fields. the last <code>&lt;/script&gt;</code> obviously closes the javascript. How can this be circumvented?</p>\n\n<pre class="prettyprint"><code> :javascript\n $(function() {\n window.router = new Dotz.Routers.ManageRouter({store: #{@store.to_json}});\n Backbone.history.start();\n });\n</code></pre>\n\n<p><strong>The above outputs:</strong></p>\n\n<pre class="prettyprint"><code>&lt;script&gt;\n //&lt;![CDATA[\n $(function() {\n window.router = new Dotz.Routers.ManageRouter({store: '{"_id":"4f3300e19c2ee41d9a00001c", "points_text":"&lt;script&gt;alert(\\"hey\\");&lt;/script&gt;"'});\n Backbone.history.start();\n });\n //]]&gt;\n &lt;/script&gt;\n</code></pre>", "answerCount": 1, "upvoteCount": 282, "dateCreated": "2012-02-12 04:12:55", "dateModified": "2022-09-18 17:04:53", "author": { "type": "Person", "name": "CamelCamelCamel" }, "acceptedAnswer": { "@type": "Answer", "text": "<p>Inside a <code>&lt;script&gt;</code> block it is syntactically illegal to have any <code>&lt;/</code> followed by a name—not just <code>&lt;/script&gt;</code>—so you need to escape that anywhere it may appear. For example:</p>\n\n<pre class="prettyprint"><code>:javascript\n var foo = { store: #{@store.to_json.gsub('&lt;/','&lt;\\/')} };\n</code></pre>\n\n<p>This will create the sequence <code>&lt;\\/</code> inside your JS strings, which is interpreted to be the same as <code>&lt;/</code>. Ensure that you use single quotes in your gsub replacement string, or else use <code>gsub( "&lt;/", "&lt;\\\\/" )</code> due to the difference between single and double quotes in Ruby.</p>\n\n<p>Shown in action:</p>\n\n<pre class="prettyprint"><code>irb:02.0&gt; s = "&lt;b&gt;foo&lt;/b&gt;" # Here's a dangerous string\n#=&gt; "&lt;b&gt;foo&lt;/b&gt;"\n\nirb:03.0&gt; a = [s] # Wrapped in an array, for fun.\n#=&gt; ["&lt;b&gt;foo&lt;/b&gt;"]\n\nirb:04.0&gt; json = a.to_json.gsub( '&lt;/', '&lt;\\/' ) # Sanitized\nirb:05.0&gt; puts json # This is what would come out in your HTML; safe!\n#=&gt; ["&lt;b&gt;foo&lt;\\/b&gt;"]\n\nirb:06.0&gt; puts JSON.parse(json).first # Same as the original? Yes! Yay!\n#=&gt; &lt;b&gt;foo&lt;/b&gt;\n</code></pre>\n\n<p>If you are using Rails (or ActiveSupport) you can enable JSON escaping:</p>\n\n<pre class="prettyprint"><code>ActiveSupport::JSON::Encoding.escape_html_entities_in_json = true\n</code></pre>\n\n<p>Seen in action:</p>\n\n<pre class="prettyprint"><code>irb:02.0&gt; a = ["&lt;b&gt;foo&lt;/b&gt;"]\nirb:03.0&gt; puts a.to_json # Without the magic\n#=&gt; ["&lt;b&gt;foo&lt;/b&gt;"]\n\nirb:04.0&gt; require 'active_support'\nirb:05.0&gt; ActiveSupport::JSON::Encoding.escape_html_entities_in_json = true\nirb:06.0&gt; puts a.to_json # With the magic\n#=&gt; ["\\u003Cb\\u003Efoo\\u003C/b\\u003E"]\n</code></pre>\n\n<p>It produces JSON that is more verbose than you need to solve this particular problem, but it is effective.</p>", "upvoteCount": 113, "url": "https://exchangetuts.com/escaping-script-tag-inside-javascript-1640376304327184#answer-1651444575181177", "dateCreated": "2022-09-12 17:04:53", "dateModified": "2022-09-18 17:04:53", "author": { "type": "Person", "name": "Phrogz" } } } }
Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Escaping </script> tag inside javascript

I'm using backbone, and the general way for passing the collections when the page load is

window.router = new Routers.ManageRouter({store: #{@store.to_json});

which is fine and works well, until someone decides to add the text "<script>alert("owned")</script>" to one of the store fields. the last </script> obviously closes the javascript. How can this be circumvented?

  :javascript
    $(function() {
      window.router = new Dotz.Routers.ManageRouter({store: #{@store.to_json}});
      Backbone.history.start();
    });

The above outputs:

<script>
    //<![CDATA[
      $(function() {
        window.router = new Dotz.Routers.ManageRouter({store: '{"_id":"4f3300e19c2ee41d9a00001c", "points_text":"<script>alert(\"hey\");</script>"'});
        Backbone.history.start();
      });
    //]]>
  </script>
like image 282
CamelCamelCamel Avatar asked Feb 12 '12 04:02

CamelCamelCamel


1 Answers

Inside a <script> block it is syntactically illegal to have any </ followed by a name—not just </script>—so you need to escape that anywhere it may appear. For example:

:javascript
   var foo = { store: #{@store.to_json.gsub('</','<\/')} };

This will create the sequence <\/ inside your JS strings, which is interpreted to be the same as </. Ensure that you use single quotes in your gsub replacement string, or else use gsub( "</", "<\\/" ) due to the difference between single and double quotes in Ruby.

Shown in action:

irb:02.0> s = "<b>foo</b>" # Here's a dangerous string
#=> "<b>foo</b>"

irb:03.0> a = [s]          # Wrapped in an array, for fun.
#=> ["<b>foo</b>"]

irb:04.0> json = a.to_json.gsub( '</', '<\/' )  # Sanitized
irb:05.0> puts json        # This is what would come out in your HTML; safe!
#=> ["<b>foo<\/b>"]

irb:06.0> puts JSON.parse(json).first  # Same as the original? Yes! Yay!
#=> <b>foo</b>

If you are using Rails (or ActiveSupport) you can enable JSON escaping:

ActiveSupport::JSON::Encoding.escape_html_entities_in_json = true

Seen in action:

irb:02.0> a = ["<b>foo</b>"]
irb:03.0> puts a.to_json # Without the magic
#=> ["<b>foo</b>"]

irb:04.0> require 'active_support'
irb:05.0> ActiveSupport::JSON::Encoding.escape_html_entities_in_json = true
irb:06.0> puts a.to_json # With the magic
#=> ["\u003Cb\u003Efoo\u003C/b\u003E"]

It produces JSON that is more verbose than you need to solve this particular problem, but it is effective.

like image 113
Phrogz Avatar answered Sep 18 '22 17:09

Phrogz