2013-07-30 22 views
10

導軌3:爲什麼to_json會在Rails 4中自動轉義unicode?

{"a" => "<br/>"}.to_json 
=> "{\"a\":\"<br/>\"}" 

導軌4:

{"a" => "<br/>"}.to_json 
=> "{\"a\":\"\\u003Cbr/\\u003E\"}" 

WHY ???

這似乎導致錯誤

Encoding::UndefinedConversionError: "\xC3" from ASCII-8BIT to UTF-8 

當我的Rails 3的應用程序試圖解析通過我的軌道4的應用程序生成的JSON。

+0

試試這個:JSON.generate({ 「A」=> 「
」}:ascii_only =>真) – user2503775

回答

9

WHY ???

爲了抵禦Web應用程序一個共同的弱點。如果您在HTML頁面中如說:

<script type="text/javascript"> 
    var something = <%= @something.to_json.html_safe %>; 
</script> 

,那麼你可能會認爲你是很好,因爲你已經JSON-逃脫你注入的JavaScript數據。但實際上你並不安全:除了JSON語法外,你也有周圍的HTML語法,並且在HTML腳本塊</中是帶內信號。實際上,如果@something包含字符串</script>你有一個跨站點腳本漏洞,因爲這出來:

<script type="text/javascript"> 
    var something = {"attack": "abc</script><script>alert('XSS');//"}; 
</script> 

第一個腳本塊通過串(留下一個未關閉字符串文字語法錯誤)和中途結束第二個<script>被視爲一個新的腳本塊,並在其中執行潛在用戶提交的內容。

JSON不需要將<字符轉義爲\u003C,但它是完全有效的替代方案,它會自動避免這類問題。如果JSON解析器拒絕它,這是讀者中的一個嚴重錯誤。

什麼是產生該錯誤的代碼?我不相信這個錯誤與<轉義有什麼關係,因爲它談論的是字節0xC3而不是0x3C。這可能表示UTF-8編碼內容沒有被標記爲UTF-8的字符串...也許你需要在輸入上使用force_encoding("UTF-8")

+5

如果你真的需要禁用JSON逃脫(假設你的情況是安全的注射),你可以這樣做: 'ActiveSupport.escape_html_entities_in_json = false' – elkelk

+0

在你的例子中,爲什麼調用'.html_safe'不是實體 - 「」到「</script >」 ?這種方法做什麼? – qntm

+1

'html_safe'實際上是相反的,它將字符串標記爲包含調用者已經保證的原始標記是安全的,因此不需要進一步轉義。如果*不*標記字符串'html_safe',那麼Rails會自動轉義它(自Rails 3以來)。 – bobince

5

您可以JSON::dump保留原來的字符串:

JSON::dump "a" => "<br/>" 
=> "{\"a\":\"<br/>\"}" 

JSON::dump "a" => "x&y" 
=> {\"a\":\"x&y\"}" # instead of x\u0026y 

小心使用它bobince提到的原因,特別是與任何用戶生成的輸入避免(或至少確保真實santized)。

下面是我遇到的一個合法用途示例。在輔助函數生成一個JavaScript哈希的說法:

# application_helper.rb 

def widget_js(post) 
    options = { 
    color: ColorCalculator(post.color).to_rgb_hex, 
    ... 
    } 
    "third_party_widget(#{JSON::dump options});" 
end