はじめに
ゼロ幅文字にエンコードした隠し情報で、文書をリークしたメンバーを特定 | 秋元@サイボウズラボ・プログラマー・ブログ
http://developer.cybozu.co.jp/akky/2018/04/leaker-detection-by-zero-width-characters/
が、とても興味深かったのでRubyで写経してみました。
どういう仕組み?
簡単に書くと次のようになります。
v = "a".ord.to_s(2) # => "1100001"
v = v.tr("01", "\u{200B 200C}") # => ""
v = v.tr("\u{200B 200C}", "01") # => "1100001"
v.to_i(2).chr # => "a"
- 文字を二進数にする
- 0 と 1 を見えない文字に変換する
- 見えない文字を 0 と 1 に変換する
- 二進数から文字に変換
たったこれだけのことですがアイデアをすぐに適用できるのはすごいなあと感心しました。
実際に埋め込んで復元するまでの流れ
埋め込みたい秘密の文字列を準備
str = "ぱくった人(id:123)"
もっとちゃんと作る場合には、改竄されてもわかるようにハッシュなどにした方がよいとのことです。
見えない文字列に変換
bin = str.codepoints.collect { |code|
code.digits(2).collect { |bit|
bit.zero? ? "\u200B" : "\u200C"
}.join
}.join("\u200D")
bin.size # => 133
bin # => ""
- U+200B, U+200C, U+200D の3つを使いました
- 本家では4つ使ってますがまだ意図がよくわかってません
- bin 変数がゼロ幅の文字列で、ブラウザ上では空文字列に見えます
- Emacsだと1文字1ドットぐらいですが何かいるのが確認できます
任意の文字列に埋め込む
text = "相手の防#{bin}衛ラインを乱したりして、得意の接近戦に持ち込もう"
text # => "相手の防衛ラインを乱したりして、得意の接近戦に持ち込もう"
埋め込んだのにブラウザ上では見えていないことがわかります。
埋め込んだ文字列から見えない文字列を抽出
bin2 = text[/[\u200B-\u200D]+/]
埋め込まれているのは一箇所だけと仮定しています。
見えない文字列から秘密の文字列に復元
bin2 # => ""
str2 = bin2.split("\u200D").collect { |str|
str.chars.collect.with_index { |char, i|
(char == "\u200B" ? 0 : 1) << i
}.sum.chr("UTF-8")
}.join
str2 # => "ぱくった人(id:123)"
正しく復元できました。
この仕組みがあれば文章のコピペを追跡しやすくなります。自衛のためのChrome拡張もありますがそれでも効果はあると思います。最近だと個人運営のゲーム攻略サイトの盗用対策として活用するのもおもしろそうです。
参照
Be careful what you copy: Invisibly inserting usernames into text with Zero-Width Characters
https://medium.com/@umpox/be-careful-what-you-copy-invisibly-inserting-usernames-into-text-with-zero-width-characters-18b4e6f17b66
ゼロ幅文字にエンコードした隠し情報で、文書をリークしたメンバーを特定 | 秋元@サイボウズラボ・プログラマー・ブログ
http://developer.cybozu.co.jp/akky/2018/04/leaker-detection-by-zero-width-characters/
その透明な文字に混じらず、見つけ出すんだ。 - Qiita
https://qiita.com/kitsuyui/items/12db383f5e5971f32b08
Whitespace character - Wikipedia
https://en.wikipedia.org/wiki/Whitespace_character
chpmrc/zero-width-chrome-extension: Replace scary zero-width characters with funny emojis
https://github.com/chpmrc/zero-width-chrome-extension