本当に大切なものは目に見えない ~Unicodeの目に見えない改行文字に苦しめられた話~


Fringe81アドベントカレンダーの4日目です。
みなさん、おはこんばんちは。Lil Pacy a.k.a ぺしおです。

前日は大先輩@pastelIncの、
『この件は誰が決めるんですか?となったときのデリゲーションポーカー』でした。

普段はElmを書いておりますが、
今回の記事では、Unicodeの少し深い浅瀬に潜ってみようと思います。
(頭悪そうな書き出しですみません。)

TL;DR

Unicodeの文字を扱う際には、「視認できない文字」や「目視では全く同じでも、実際は全く別の文字」が存在していてセキュリティ上のリスクにも繋がるので注意が必要である。

今回苦しめられたあいつ


←こいつのこと





↑こいつのこと

こいつのこと→

やはり、どう頑張っても目に見えない、プレビューに表示されない。
というかQiitaのエディタに貼っつけると消されてしまう。

事の発端

slackのメッセージが勝手に改行される問題

SlackBotの表示がバグってしまっていた

ログに表示しても何かが入ってるようには見えない

Block Kit Builderにコピペしてみる

やはり、改行されてしまう

よくよく右側を見ると...

Gotcha!!(捕まえた!!)

この赤丸、そのままコピペで検索しても何も出てこなかったため一旦パーセントエンコーディングしてみた。

js
encodeURI('');
// => "%E2%80%A8"

"%E2%80%A8"こいつでググってみるとU+2028というUnicodeの改行文字だとわかった

今回は、リプレイスして解決。

js
str.replace(/\u2028/g,'')

他にも色々

出典:一般句読点 General Punctuationの文字一覧 | 0g0.org

下の方もおそらく改行

捕まえる方法

toUnicode関数を使う

js
function toUnicode(theString) {
  var unicodeString = '';
  for (var i=0; i < theString.length; i++) {
    var theUnicode = theString.charCodeAt(i).toString(16).toUpperCase();
    while (theUnicode.length < 4) {
      theUnicode = '0' + theUnicode;
    }
    theUnicode = '\\u' + theUnicode;
    unicodeString += theUnicode;
  }
  return unicodeString;
}

出典:Convert a String to Unicode in Javascript

こいつで

js
toUnicode('');
// => "\u2028" Qiitaの記事上では何かが入っているようには見えないけれど。

ちなみにUnicodeを対応するStringにする方法

js
function unicodeToChar(text) {
   return text.replace(/\\u[\dA-F]{4}/gi, 
          function (match) {
               return String.fromCharCode(parseInt(match.replace(/\\u/g, ''), 16));
          });
}

出典:Converting unicode character to string format

js
unicodeToChar('\u2028')
// => "" やっぱり目には見えないんだけれどね。

結論

本当に大切なものは目に見えない(星の王子様風に

Tips

以下、Unicodeでセキュリティ上考慮しないといけないことに触れた記事。

Unicode ゼロ幅スペースを利用して情報を隠して仕込む - A painter and a black cat
Unicodeで絶対知っておくべきセキュリティ5つの注意(翻訳)
人間の目で見抜けないURL偽装がフィッシング詐欺に悪用される可能性、Firefoxでの対策はコレ - GIGAZINE

P.S.

Macなら以下のコマンドでUnicodeの2028番を生成してクリップボードにコピーできる

$ echo -en "\u2028" | pbcopy

ぜひいろんなところにはっつけてみていただきたい。

以上。