2016-09-21 7 views
0

jsonで安全にhtmlのようなテキストをエンコードするのに苦労します。テキストは<textarea>に書き込まれ、ajaxによってサーバー(.net45 mvc)に転送され、json-stringでデータベースに格納されます。Json.netのトラバースとHtmlEncode文字列C#

サーバーに転送すると、有名な「潜在的に危険なRequest.Form値が検出されました」500のサーバーエラーが発生します。このメッセージが表示されないようにするには、転送されるモデルで[AllowHtml]属性を使用します。そうすることで、XSSの脆弱性が解消されます。その場合は誰でも{ "key1": "<script>alert(\"danger!\")</script>" }に貼り付けてください。そのため、私は

tableData.Json = AntiXssEncoder.HtmlEncode(json, true); 

問題は、それはもちろん私が欲しいものではありません

{&#13;&#10;&quot;key1&quot: ...} 

のようなものをレンダリングするように私は、完全なJSON文字列にこれを行うことはできませんあるようなものを使用したいと思います。これは、ユーザーが、彼らが好きなコード書くことができますが、私は、HTMLとしてレンダリングされることを回避することができ、かつ普通のテキストとして、それを表示するには、この結果では、より

{ "key1": "&lt;script&gt;alert(&quot;danger!&quot;)&lt;/script&gt;" } 

ようにする必要があります。誰もが文字列がAntiXssEncoder.HtmlEncode(... , ....);でエンコードできるようにC#(Newtonsoft Json.NET)でjsonをトラバースする方法を知っていますか?または私は間違ったトラックにここにいますか?

編集:

  1. オプションではありません均一なオブジェクトに逆シリアル化のためのデータは、不均一です。
  2. データは一般に公開されるため、エンコードされたデータを保存すると自分の魂が楽になります。
+0

[デシリアライズ時にHTMLで選択的にエスケープする](http://stackoverflow.com/q/32562381/10263)をご覧ください。それはあなたの状況に似て聞こえる。あなたは、ニーズに合わせてソリューションを適応させることができます。 –

答えて

0

すでにJSON文字列としてデータを持っている場合、あなたはJsonConvert.DeserializeObject()使用Json.NETようなもので、適切なオブジェクトにそれを解析でき(または何か他のものを、から選択するかなりの数のオプションが実際にあります)。一度それが普通のオブジェクトであれば、それらを通り、必要なエンコーディングを適用してから、JSON文字列に再度シリアル化することができます。 this questionとその回答もご覧ください。

あなたが取るかもしれないもう1つのアプローチは、ページDOMに実際に物を挿入するまでそれをそのまま残すことです。エンコードされていないデータをデータベースに保存することもできます。JSONデータとしてHTMLエンコーディングを使わずにクライアントに送信することもできます(JSON用にエンコードする必要がありますが、シリアライザではそれを行います)。この方法で直接ページソースに生成しないように注意する必要がありますが、text/jsonコンテンツタイプのAJAX応答であれば問題ありません。その後、クライアント上で実際のテキストエリアに挿入する場合は、htmlではなくテキストとして挿入する必要があります。技術的にはこれはjQueryの.text()代わりの.html()、または溶液の関連するメソッドバインディングテンプレートエンジンのか、クライアント側のデータ(剣道UI言うにtext:の代わりに、ノックアウトでhtml:#:代わりの#=を、など)

利点を使用して意味するかもしれません後者のアプローチは、データを送信するときに、サーバー(APIのようなもの)がクライアントがデータをどこでどのように使用するかを気にする必要がないことです。クライアントは、HTMLまたはJavascriptのコンテキストに対して異なるエンコーディングが必要な場合があります。サーバーは必ずしも適切なものを選択することはできません。

このデータが必要なテキスト領域であることが分かっていれば、当然のことながら、最初の(元の)アプローチを使用してサーバー上でエンコードすることもできます(それは、シナリオ)。

この質問に答える際の問題は、詳細数が、多くがであることです。理論的には、あなたがそれを正しく行うことができる方法はたくさんありますが、良い解決策は、脆弱な解決策と1つの文字で異なる場合があります。

+0

ありがとうございました。 データは一様ではなく、公開される可能性があります。 このように、デシリアライゼーションは動的オブジェクトにつながり、新しい一連の質問がそれ自身で発生します。他の人がデータを使用する可能性があるので、すぐに安全なデータとして保存する方が良いと思います。 私は現在、json-stringをJTokenオブジェクトとしてトラバースし、typeがJTokenType.Stringと等しいところにあるすべての値をエンコードする非再帰的アプローチを試みています。 – pekaaw

0

これは私が行った解決策です。 ViewModelに[AllowHtml]という属性を追加しました。これにより、テキストエリアから生のhtmlを(ajaxを通して)送信することができました。 この属性を使用すると、MVSがXSSの危険から守るために与えるSystem.Web.HttpRequestValidationExceptionは避けられます。 そしてIはJTokenとしてそれを解析して、JSON文字列を横断し、文字列をエンコードする:

public class JsonUtils 
{ 
    public static string HtmlEncodeJTokenStrings(string jsonString) 
    { 
     var reconstruct = JToken.Parse(jsonString); 
     var stack = new Stack<JToken>(); 
     stack.Push(reconstruct); 

     while (stack.Count > 0) 
     { 
      var item = stack.Pop(); 
      if (item.Type == JTokenType.String) 
      { 
       var valueItem = item as JValue; 
       if(valueItem == null) 
        continue; 

       var value = valueItem.Value<string>(); 
       valueItem.Value = AntiXssEncoder.HtmlEncode(value, true); 
      } 

      foreach (var child in item.Children()) 
      { 
       stack.Push(child); 
      } 
     } 
     return reconstruct.ToString(); 
    } 
} 

得JSON文字列がまだ有効であろうと私はDBに格納します。今、それをビューで印刷するとき、JSのJSONから直接文字列を使用できます。 別の<textarea>で編集用にもう一度開くと、htmlエンティティをデコードする必要があります。そのために私はいくつかのjsコード(decodeHtmlEntities)を "stole"してstring.jsから削除しました。もちろん、ライセンスとクレジットメモを追加する。

これは誰にも役立ちます。

関連する問題