【トラブル】【JavaScript】C3.jsのTooltipがXSSに対応していないので対応する

TooltipがXSSに対応していない

https://github.com/masayuki0812/c3/issues/1536
にあるように、グラフについては、XSSに対応しているようだが
Tooltipに関しては未対応の模様。

サンプル : XSS未対応版

alert("XSS" )が表示する
<html>
<head>
<meta charset="UTF-8">
<!-- Load c3.css -->
<link href="./c3/c3.css" rel="stylesheet" type="text/css">
<!-- Load d3.js and c3.js -->
<script src="http://d3js.org/d3.v3.js" charset="utf-8"></script>
<script src="./c3/c3.js"></script></head>
</head>
<body>
<div id="chartToDrow"></div>
<script>
var chart = c3.generate({
  bindto: '#chartToDrow',
  data: {
      columns: [
          ['data1"><img src="dummy.jpg" onerror="alert(\'XSS\')" />"', 130, 100],
          ['data2', 150, 50],
      ],
      type: 'bar'
  },
});
</script>
</body>
</html>

解決案

 * 以下の関連記事の「■ 独自のTooltipを実装するには」と「JavaScript でのサニタイジング(エスケープ)」
   を使って、修正してみる
独自のTooltipを実装するには
http://blogs.yahoo.co.jp/dk521123/35526974.html
JavaScript でのサニタイジング(エスケープ)
http://blogs.yahoo.co.jp/dk521123/35778596.html

解決案サンプル : XSS対応版

エスケープした
<script>
var chart = c3.generate({
  bindto: '#chartToDrow',
  data: {
      columns: [
          ['data1"><img src="dummy.jpg" onerror="alert(\'XSS\')" />"', 130, 100],
          ['data2', 150, 50],
      ],
      type: 'bar'
  },
  // ★ここ★
  tooltip: {
      contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
        var $$ = this,
            titleFormat = defaultTitleFormat,
            nameFormat = function (name) { return name; },
            valueFormat = defaultValueFormat,
            text, i, title, value, name, bgcolor;
        for (i = 0; i < d.length; i++) {
            if (! (d[i] && (d[i].value || d[i].value === 0))) { continue; }

            if (! text) {
                title = titleFormat ? titleFormat(d[i].x) : d[i].x;
                text = "<table class='c3-tooltip" + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
            }

            value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
            if (value !== undefined) {
                name = nameFormat(d[i].name, d[i].ratio, d[i].id, d[i].index);
                bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
                
                var targetId = escape(d[i].id);
                text += "<tr class='c3-tooltip-name" + "-" + targetId + "'>";
                text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + escape(name) + "</td>";
                text += "<td class='value'>" + escape(value) + "</td>";
                text += "</tr>";
            }
        }
        return text + "</table>";
      }
  },
});

function escape(targetValue) {
  if (targetValue === null || targetValue === undefined) {
     return "";
  }
  return String(targetValue)
     .replace(/&/g, "&")
     .replace(/"/g, """)
     .replace(/'/g, "'")
     .replace(/`/g, "`")
     .replace(/</g, "<")
     .replace(/>/g, ">");
}
</script>
</body>
</html>