2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Symbol のウォレットとノードを同じ PC で動かしても、アカウントと結びつかないようにした話

2
Posted at

自作の Symbol(XYM)のウォレット、heika には、ノードも入っている。ボタンひとつで、自分の PC の中でノードを動かせる。自分のノードに残高を聞けば、どこかの REST を信じなくて済む。ハーベストも自分のノードでできる。便利である。便利なのだが、ひとつ気になることがあった。

ノードを動かすと、その PC がネットワークに顔を出す。 ほかのノードとつながる以上、IP アドレスは相手に見える。そこに財布のアカウントが結びついてしまったら、「この IP の人は、このアカウントでこれだけ持っている」が筒抜けになる。それはちょっと、いやぁ……その、やだよねぇ……うん、無理😇

なので heika では、「ノードからアカウントに足がつかない」ことと、「PC を見られても、隠しアカウントがあると言い切られない」ことに気を配った。この記事は、その配慮の一覧である。

ノードの鍵は、財布と関係のない鍵にする

Symbol のノードには鍵が 2 つある。

  • メインの鍵(CA の鍵): ノードの持ち主として名乗る鍵。エクスプローラーのノード一覧に「メインアカウント」として出る
  • ノードの鍵(TLS の鍵): ほかのノードとの通信に使う鍵。委任ハーベストの NodeKeyLink は、こちらにつなぐ

catapult(Symbol の本家のノード)を shoestring で立てるときは、CA の鍵に自分のアカウントの鍵を使うこともできる。持ち主がはっきりするので、ノードを公開して運用するならそれもありだ。

でも、自分の PC でこっそり動かすノードでそれをやると、ノードの一覧に自分のアカウントが載る。IP アドレスつきで。

heika のウォレットは、初めてノードを起動するときに、CA の鍵もノードの鍵も、財布とは関係のない新しい鍵として作る。なので、エクスプローラーでノードのメインアカウントを見ても、そこにあるのは残高 0 の知らないアカウントだ。財布のアカウントとは、チェーンの上ではどこもつながっていない。

ちなみに、これで「ノードのメインアカウントが、取り込んだアカウントと違う!」と戸惑われた方がいらっしゃったようだ。そう、違うのである。わざとなのである。説明不足。一応ごめんなさいしておこ。ごめんなさい……🙇💦💦💦

外から探されにくくする

ウォレットの中のノードは、P2P も REST も、この PC の中(127.0.0.1)だけで待ち受ける。外から話しかけることはできない。ノードのほうから、ほかのノードにつなぎに行くだけだ。

それでも、つないだ相手のノードには「こういうノードがいる」と覚えられて、ピアの一覧に載る。これは P2P でつながる以上、避けられない。避けられないのだが、名乗る中身は減らせる。

Symbol のノードは、ほかのノードに自分の役割(roles)を名乗る。

  • Peer: ブロックやトランザクションをやりとりする
  • Api: REST を立てている。財布やクローラーは、この印を見て REST を探しに来る

heika のノードは、REST の口があれば Api を名乗る作りだった。ウォレットの中のノードにも、自分のノードに残高を聞くための REST がある。ただしこの PC の中だけの口だ。なので、外からは届かない REST を「ありますよ」と宣伝していたことになる。探しに来た人は空振りするし、こちらとしても目立つだけで、誰もはっぴーにならない。それさすがにやだ。

これは使っている方からご指摘をいただいて気づいた。ありがとうございます! v0.12.0 から、ウォレットの中のノードは Peer だけを名乗る。

Peer のほうは、外からつなげなくても名乗ったままにした。NAT の内側にいて、自分からつなぎに行くだけのノードも、Peer を名乗る。そういうノードは珍しくないので、目立ちにくい。木を隠すなら森の中である🌲

鍵を持つウォレットと、外としゃべるノードを、プロセスで分ける

ノードは、知らない相手から届いたバイト列を朝から晩まで読み続ける。どこかに読み方の穴があれば、狙われるのはそこだ。そこと同じプロセスに、ニーモニックを開いたウォレットがいるのは落ち着かない。

なので、パソコン版では、ノードをウォレットとは別のプロセスで動かす。別の実行ファイルは配っていない。ウォレットが自分自身を --node <設定ファイル> で起動し直して、子のプロセスがノードになる。

  • ウォレットのプロセス: キーストアを開き、署名する。ほかのノードとブロックをやりとりしない
  • ノードのプロセス: ほかのノードとやりとりする。キーストアは持たない

子には、標準入力の管でだけ話しかける。ハーベストの鍵も、この管で渡す。親が落ちれば管が閉じるので、子は今のブロックを書き終えてから止まる。ノードだけが取り残されて動き続けることはない。

万が一ノードのほうに穴があっても、別のプロセスのメモリにあるニーモニックまでは、すぐには手が届かない。もちろん、同じユーザーで動いている以上、完全な壁ではない。それでも、一枚あるとないとでは大違いである🧱。OSカーネルが隔離してくれるもん✨。でもカーネルエクスプロイトはこゎぃ……。

残高は、自分のノードに聞ける

ウォレットは、残高を見るにも送金するにも、どこかのノードの REST に話しかける。ふつうは、外の誰かのノードだ。

すると、その REST の持ち主には「この IP の人が、このアドレスの残高を見ている」がわかる。表の財布と隠しアカウントを同じ REST で見れば、その 2 つが同じ人のものだということまでわかる。ログを取っていなければ大丈夫だが、取っているかどうかは、こちらからは見えない。

heika のウォレットは、設定で選べば、残高も送金の確かめも、自分のノードの REST(この PC の中)に聞く。誰がどのアドレスを見ているかは、PC の外に出ない。冒頭で「どこかの REST を信じなくて済む」と書いたが、信じなくて済むだけでなく、見られなくて済むのである👀✨

ハーベストの鍵は、ノードのメモリにだけ渡す

ウォレットの「このノードでハーベスト」を押すと、財布のアカウントに、リモートの鍵と VRF の鍵をリンクする。

  • 2 つの鍵は、キーストアに入っている Harvest-Secret から作る。財布の鍵そのものではない
  • ノードには、メモリだけで渡す。ディスクには書かない。ノードを止めれば消えるので、起動し直したら渡し直す
  • チェーンに送るのは、AccountKeyLink と VrfKeyLink だけ。NodeKeyLink は送らない

最後のところがだいじだ。外のノードに委任するなら NodeKeyLink が要るが、自分のノードでハーベストするのに、自分のノードの鍵をチェーンに書く必要はない。書いたら最後、「このアカウントはこのノードの人」と永遠に残る。リンクを外しても、記録は消えない。ブロックチェーンは忘れてくれないのである。私も気をつけよ……。

ディスクに手がかりを残さない

heika の財布は、BIP39 のパスフレーズ(いわゆる 25 番目の単語)で開く「隠しアカウント」を使える。同じニーモニックでも、パスフレーズが違えば、まったく別のアカウントになる。誰かにパスフレーズなしで開けと言われても、表の財布だけを見せられる。

ただし、これが効くのは、隠しアカウントがあった痕跡がどこにもないときだけだ。PC の中に隠しアカウントのアドレスがひとつでも残っていたら、「ほかにもありますよね?」と言われて終わる。

なので、heika はディスクに書くものを絞っている。

  • キーストアは暗号化する。 パスフレーズで暗号化した age の形式で、heika がなくても age -d で開ける(heika がなくなっても困らない)。書いている途中で落ちても、ファイルが壊れないように書く
  • 送った控えは、メモリにだけ置く。 隠しアカウントからの送金がファイルに残ると、隠しアカウントがあることを否認できなくなるからだ。控えが要るのは期限(2 時間)までなので、それより長く覚えておく理由もない
  • 設定ファイルには、アドレスを書かない。 最後に開いたアカウントは、アドレスではなく、キーストアの中の番号で覚える

じつは最後のは、最初はアドレスで覚えていた。気づいたときは、この絵文字のようになった→ 😱 今は直っている。Got ことなき、だといいな……。

秘密の扱い

細かいけれど、地味だけど、それでもだいじなこと。

  • 秘密鍵は、使い終わったらメモリから消す(Rust の zeroize)
  • CLI では、秘密鍵を引数では受け取らず、標準入力からだけ読む。シェルの履歴に残らないように
  • 送る前に、下書きを画面で確かめてもらってから署名する

まだできていないこと

ちゃんと正直に書いておく。

  • ハーベストしたブロックは、最初にそのノードから流れる。 チェーンには IP は残らない。でも、つながっていたピアの側で「このブロックはこの IP から最初に来た」と見られれば、ハーベストしたアカウントの見当はつく。ここは今のところ防いでいない
  • 送金も、最初はそのノードから流れる。 自分のノードから送れば、ハーベストのブロックと同じく、ピアの側で「このトランザクションはこの IP から最初に来た」と見られうる。外の REST から送れば、今度はその REST の持ち主に見える。今のところ、どちらにしても、どこかには見える
  • Android では、プロセスを分けていない。 Android のアプリは実行ファイルではなく、Java から読み込まれるライブラリなので、自分を起動し直せない。今は、ノードをアプリのプロセスの中のスレッドで動かしている
  • 自分のノードに外から委任すると、結びつく。 別の財布から、自分の heika のノードあてに NodeKeyLink を送れば、そのアカウントとノードはチェーンの上で結びつく(そもそも、ウォレットの中のノードは委任を引き受けないので、ハーベストも始まらない)。外へ委任する画面を作るときに、ちゃんと説明を出さなきゃ……。

おわりに

「便利なものを作ったら、足がつくようになった」では悲しい。自分のデバイスでノードを動かすのが当たり前になるなら、そのぶん気を配るところも増える。今回はその気をつけることリストを書いてみた。

抜けているところに気づいたら、ぜひ教えてほしい。いやその私に抜けてるところがあるのはもうわかってるから、今回の roles の件のように、教えてもらって初めて気づくことはけっこうある。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?