JSON-RPC パスワード

JSON-RPC にパスワードを追加する変更を SVN にアップロードした。ビルド環境がある方は、テストしてほしい。

-server スイッチは -rpcpw=<password> に置き換えられ、bitcoind でも使用される。 bitcoin -rpcpw= — JSON-RPC ポートを開いて実行 bitcoind -rpcpw= — パスワード付きデーモン

スイッチ名のより良いアイデアがあれば知らせてほしい。ただし、データベースの暗号化用のパスワードもいずれ必要になることを念頭に置いてほしい。確信はないが、2 つのパスワードを別々に使いたい人もいるかもしれない。

パスワードを設定しないと警告が表示される。

すべてのコマンドで最初のパラメーターとしてパスワードが必要になった。bitcoind help を実行するとその旨が表示される。

中核コード:

  // パスワード確認
  if (params.size() < 1 || params[0].type() != str_type)
      throw runtime_error("First parameter must be the password.");
  if (params[0].get_str() != strRPCPassword)
  {
      if (strRPCPassword.size() < 15)
          Sleep(50);
      begin = strRequest.end();
      printf("ThreadRPCServer incorrect password attempt
");
      throw runtime_error("Incorrect password.");
  }

これらの判断についてコメントはあるか?

  1. if (strRPCPassword.size() < 15) Sleep(50); — これは短いパスワードの場合、各試行後に 50ms 待機することを意味する。これは DoS 攻撃に利用される可能性があるが、短いパスワードの場合はブルートフォースのパスワードスキャンから保護する方が重要だと判断した。これにより外部の人にパスワードが 15 文字未満かどうかがわかってしまう可能性があるが、15 文字未満はそれほど注目すべきことではなく、ほとんどのパスワードは 15 文字未満だ。DoS の可能性を閉じたい場合は、15 文字以上のパスワードを使用してほしい。

  2. begin = strRequest.end(); — 複数の呼び出しを含む単一のリクエストの場合、1 つが不正なパスワードであれば残りを破棄する。これは 1 つのパケットに何百万ものパスワード試行を詰め込めないようにするためだ。これは正しい判断だと思うか?(複数呼び出しはほとんど使われないと思うが)

ヘルプに重複して表示されていた 2 つのコマンドも修正した:

getaddressesbylabel

リモートで行う分にはまあいいが、同じ Unix マシン上の他のユーザーからビットコインを盗まれることが心配なら、これでも解決しない。/proc、top、ps などでコマンドラインが見えるからだ。少なくともそれを防ぐために、stdin でパスワードを読むか、readline を使うなどすべきだろう。コマンドラインで渡せるようにするのは良くないと思う。

さらに良いのは鍵ファイルを使うことだろう。そうすれば Unix のパーミッションでそのユーザーだけが読めるようにできる、ssh みたいに……bitcoind に authorized_keys ファイルを持たせ、公開鍵を置けばいい。ともかく、嫌味を言うつもりはないが、コマンドラインでのやり方は偽りのセキュリティ感にすぎない。

確かに、それはかなり良いですね。

そのようにやっている他のソフトの例を教えていただけますか?(コマンドラインがどのように見えるか)

ここで主に話しているのは、bitcoind を起動する際に -rpcpw= を使う代わりに、テキストファイルを指定してそこから読み取るスイッチを使うということですね?(スイッチの名前のアイデアはありますか?)

Bitcoin Faucet(本番と TEST)はこの変更を適用して稼働中だ。

パスワードがコマンドラインでは最後に指定するのに、JSON-RPC のパラメーターリストでは最初になるので少し混乱した。コマンドラインのパスワードをファイルから読み取る方が便利で安全だという意見には同意する。

他のプロジェクトが JSON-RPC 認証にどう取り組んでいるか調査してみるつもりだ。

Transmission の BitTorrent クライアントは認証付き JSON-RPC を実装している。「Remote Control」セクションを参照: https://trac.transmissionbt.com/wiki/ConfigurationParameters

例えば、setting.json ファイルは次のようになる:

{
    "rpc-enabled":1
    "rpc-authentication-required": 1,
    "rpc-password": "xxxxxxxxxx",
    "rpc-port": 9091,
    "rpc-username": "xxxxxxxxxx",
    "rpc-whitelist-enabled":1
    "rpc-whitelist":"127.0.0.1,192.168.*.*"
}
HTTPの「basic」認証(HTTPヘッダーにAuthorization: basic base64(username:password))を使用している。

さらに調査した結果……Transmission のアプローチと、既存の「127.0.0.1 からの接続のみ許可」を組み合わせるのが、短期・中期的には良い解決策だと思う。

Bitcoin ディレクトリ内の settings.json ファイルに username:password を置く方式はうまく機能するはずだ(Bitcoin はすでに JSON をパースできるので)。認証をコマンドラインから HTTP ヘッダーに移し、JSON リクエストパラメーターの代わりにトランスポート層に置くのはすっきりしていて良い。

長期的には、認証付きセキュア JSON-RPC の「正しい」方法はクライアント側証明書と https だ。しかし、実装には多大な作業が必要で、ユーザーがクライアント側証明書の生成方法や JSON-RPC 接続の両端での使用方法を理解するのは大きな学習曲線となる。そして、本格的なクライアント証明書ソリューションが、悪意のある Javascript が XMLHttpRequests で localhost に JSON-RPC リクエストを送る問題を解決するかどうかさえ確信が持てない。もしユーザーがブラウザーにクライアント証明書をインストールしたら(JSON-RPC ベースの Web フロントエンドがあったとして)、悪意のあるウェブサイトがリクエストを送った時にブラウザーは自動的にクライアント証明書を送信するだろうか?

~/.bitcoin ディレクトリに設定ファイルを置くということだな、それは良さそうだ。「パスワードが設定されていない」の警告で、ファイルの場所と何をすべきかを伝えることができる。

最も普及していて一般的な設定ファイル形式は何だろうか?

HTTP ベーシック認証を検討すべきだ。ただし実際には、HTTP や JSON-RPC のラッパーの追加パラメーターを通じてパスワードを指定する方法を理解するのは、パラメーターリストの先頭に追加パラメーターを付けるよりもウェブ開発者にとって手間がかかる。どう思うか?HTTP ベーシック認証には追加のメリットがあるか?パラメーターリストから移動しても、より難解な場所で指定する必要があるのでは、純粋な改善とは言えないかもしれない。

ギャビン・アンドレセンの投稿(2010年7月19日 03:02 UTC)

パスワードがコマンドラインでは最後に指定するのに、JSON-RPC のパラメーターリストでは最初になるので少し混乱した。コマンドラインのパスワードをファイルから読み取る方が便利で安全だという意見には同意する。

あなたにも混乱させられている。どういう意味だ?何か意図しない動作があったのか?

サトシ・ナカモトの投稿(2010年7月19日 07:20 UTC)

~/.bitcoinディレクトリに設定ファイルを置くということだな、それは良さそうだ。「パスワードが設定されていない」の警告で、ファイルの場所と何をすべきかを伝えることができる。

難しい質問だ!最も一般的:おそらく Windows INI ファイルだろう。Windows が OS として最も普及しているから。

JSON を推したい。JSON は(ほぼ)YAML のサブセット(YAML は設定ファイルの一般的な選択肢)なので、JSON または YAML パーサーで読める。 最大の利点は認証をトランスポート層に適切に配置することだと思う。そうすれば将来、本格的な HTTPS と証明書を導入する場合に API を変更する必要がない。 いや、単に「command」と「parameter」を混同して、こうしただけだ:

> bitcoind help
error: First parameter must be the password.
> bitcoind <my password> help
error: unknown command: <my password>
>bitcoind help <my password>
 ... that works.

bitcoind はもっとシステム全体のデーモンにすべきではないか?PAM 認証で、実行ユーザーだけでなくすべてのシステムユーザーをサポートする。 例えば/home/*/.bitcoin フォルダーのウォレットファイルをスキャンして、ユーザー名とシステムパスワードの両方でアクセスを提供するとか……

自分で書いた別の JSON-RPC クライアントを使うならパスワードの保護に気をつけられるが、bitcoin バイナリをクライアントとして使ってコマンドラインでパスワードを渡すのは、デーモン起動時と同じ問題がある。どちらの方法でもすべてのユーザーに見えてしまう。

だからサーバーモードとクライアントモードの両方の起動でファイルを使い、コマンドラインでパスワードを受け付けないようにする必要がある。一般的にこの種のプログラムは、ファイルのパーミッションが 600 でなければ起動を拒否する。他のユーザーが読めることを意味するからだ。

Linux で最も一般的な設定ファイル形式が何かまだ知りたい。標準のファイル拡張子はあるか?JSON を使った設定ファイルは見たことがなく、すべてをクォートで囲む必要があり(キーも含めて)、人間にとってあまり親切には見えない。私がよく見るのはこのような形式だ:

# コメント
setting=value

Boost に設定ファイル関連のものはあるか?

コマンドラインからクライアントとして bitcoind を使ってコマンドを発行する場合、その時も設定ファイルからパスワードを取得できるようにできるか?

ギャビンに指摘されたが、CommandLineRPC の数字の列をインクリメントするのを忘れていたため、現在の -rpcpw= の実装はコマンドラインからの文字列以外のパラメーターでは正しく動作しない。(JSON-RPC は問題ない)まだ開発中だ。

設定ファイル形式を調査していた。比較を以下に示す。

YAML は巨大だ。プロジェクトに統合できる軽量で簡単にビルドできるライブラリがあるかどうかわからない。過剰に思える。

JSON は魅力的で好む傾向にあるが、2 つの主要な問題点がある:

  1. コメントがない!行をコメントアウトして無効にできない設定ファイルなんてどうやって使うのか?
  2. キーを含むすべての文字列を”クォート”で囲む必要があり、行末のカンマも忘れずに付けなければならないのは、あまりユーザーフレンドリーではない。
{
    "key" : "value",
}

設定ファイルを 1 行ずつ読み込んで、#文字(および/または”//”?)の位置で行を切り詰め、文字列に連結して JSON に渡すことで、簡単に JSON を前処理できるだろう:

# コメント
"key" : "value",   # カンマは忘れずに
"key2" : "value",   // このようなコメントや両方

Boost には boost::program_options がある。

行を自分で読み取って map<string, string> mapConfig に入れることもできる。

while (!eof)
  行を読み込む
  '#'が見つかったら行を切り詰める
  最初の':'で行を分割 -> key, value
  mapConfig.insert(key, value)

構文として:

# コメント
key : value

を使い、キーの前に空白インデントを許可しなければ、YAML のサブセットとなり、より複雑な機能が必要になった時に YAML に切り替えることができるだろう。

自前パースにした場合でも、必要に応じて特定のパラメーター値に JSON を使用できないわけではない。オプションがリストやより構造化されたデータを必要とする場合、その値を JSON としてパースできる:

key : ["item1", "item2", "item3"]

ただし、すべて 1 行に収める必要がある。

自前パースの mapConfig に傾いている:

# コメント
key : value
lachesis 2010年7月21日 06:52 UTC 原文 ·

最もシンプルな Linux 設定ファイルは通常、以下のようなフォーマットだ:

# how often (in minutes) data is saved when all interface are offline
OfflineSaveInterval 30

# force data save when interface status changes (1 = enabled, 0 = disabled)
SaveOnStatusChange 1

# file used for logging if UseLogging is set to 1
LogFile "/var/log/vnstat.log"

# file used as daemon pid / lock file
PidFile "/var/run/vnstat.pid"

標準の拡張子は、あるとすれば.conf だ。ハッシュ(#)が圧倒的に最も一般的なコメント文字だ。セミコロンや C スタイルのコメントも見かける。

ウォレットの一部ではない、人間が操作しやすい設定ファイルがあれば大きな前進だと思う。現在コマンドラインで指定されている多くのオプション(例えば noirc や -minimizetotray)は、設定ファイルで指定した方が良いかもしれない。

Linux には「典型的な」設定ファイルというものはないと思う!

自分の Debian システムの/etc にある 20個の.conf ファイルを手短に調べてみたところ: 1 ファイルは”key value”を使用 5 ファイルは”key=value”を使用(実際にはいくつかは”key = value”で、”=“の前後にスペースを許容) 14 ファイルは独自の方式

独自の方式の 14 ファイルは実に様々で、1 行 1 値から”key:value”、本格的な XML まであった。#は Linux 世界における共通のコメント文字だ。

私の推しは:

# comment
key1=value1
ギャビン・アンドレセンの投稿(2010年7月21日 03:11 UTC)

Linuxには「典型的な」設定ファイルというものはないと思う!

1 ファイルが”key value”を使用 5 ファイルが”key=value”を使用 調査ありがとう!

「key value」は少し不自然に感じる。キーと値の間に、代入を示唆するより明確な区切りがあるべきだ。スペースを使う人は、自分の言語の split 関数を使って手を抜いているだけかもしれない。

key=some full sentence with spaces in it.  # こちらの方がより明確
key some full sentence with spaces in it.  # これよりも

それでは、自前パースの mapConfig で行こう。構文:

# コメント
key=value

ファイル拡張子は.conf。ファイル名は~/.bitcoin/settings.conf か、それとも~/.bitcoin/bitcoin.conf か、それとも他の何かか?

キーと値の先頭と末尾の空白を除去した方が良いと思う。

# カラム整形が好きなユーザー
k            = value
key         = value
longerkey =   this sentence would be this    # "this sentence would be this"
        key = value   # これも大丈夫だろう
  nextkey = value
      right = justified

通常の構文は key=value にすべきだが、時々 key = value にする人を責めることはできない。

boost::program_options は同じ key=value 形式を持っている。ギャビンが指摘したように、型付き値抽出のような難解な C++構文に踏み込むことなく、シンプルなパーサーとして使用できる。後で必要に応じてより多くの機能を使うことができる。

パラメーターとしてのパスワードではなく、HTTP ベーシック認証で進めよう。

この実装を自分から引き受けて、今日かなり進捗があった。サトシ:明日にはパッチを送れるはずだ。

完了:Bitcoin が{BITCOIN_DIR}/bitcoin.conf ファイルから設定を読み込めるようにした。-conf=path_to_config_file.confコマンドラインオプションも追加した。 完了:Bitcoin RPC に HTTP Basic 認証を要求させ、ユーザー名・パスワードが間違っているリクエストを拒否するようにした。

TODO:Bitcoin のコマンドラインからAuthorization:ヘッダーを追加するようにする。コマンドラインから Bitcoin を操作する際にユーザー名・パスワードを入力する必要はなく、bitcoin.conf から読み取って適切に処理する。 TODO:rpc.user/rpc.password が設定されていない場合、ダイアログボックスまたは debug.log で設定方法を説明する警告を表示する。 TODO:rpc.password が 15 文字未満の場合、パスワード推測の試行を制限する。 TODO:JSON-RPC の Wiki ページを更新する。

以上すべてが完了してサトシにパッチを送った後、bitcoin.conf にいくつか追加する予定だ:

port= # listen ポートの設定(デフォルト 8333 を上書き) rpc.port= # JSON-RPC ポートの設定(デフォルト 8332 を上書き)

既存の -datadir オプションと合わせれば、1 台のマシンで複数の Bitcoin を実行しやすくなる。

lachesis 2010年7月22日 01:27 UTC 原文 ·

素晴らしいよ、ギャビン。このスレッドで設定ファイルのオプション案のリストを作り始めるべきだ。

まず、noirc(デフォルトオフ)オプションとminimizetotrayオプションを提案する。どちらも同名のコマンドラインスイッチと同じことをする。毎回 -minimizetotray を付けて Bitcoin を起動するハック的なやり方をやめられる。あと、-server-daemon にも同様のオプションがあるべきでは?

すべてのコマンドラインオプションを bitcoin.conf ファイルでも指定できるように実装した。

コマンドラインで指定されたオプションは conf ファイルのオプションを上書きする。ただし、特に addnode のような「複数引数」オプションについてはもっとテストが必要だ。

ギャビン・アンドレセンの投稿(2010年7月21日 16:11 UTC)

この実装を自分から引き受けて、今日かなり進捗があった。サトシ:明日にはパッチを送れるはずだ。

この RPC 関連の多くのコンテキストでは、fprintf(stdout でコンソールに出力できる。このように:

#if defined(__WXMSW__) && wxUSE_GUI
        MyMessageBox("Warning: rpc password is blank, use -rpcpw=<password>
", "Bitcoin", wxOK | wxICON_EXCLAMATION);
#else
        fprintf(stdout, "Warning: rpc password is blank, use -rpcpw=<password>
");
#endif

RPC wiki ページを更新して、Bitcoin 0.3.3 でのパスワード機能の仕組みを説明した。

1 つの良い副作用:今すぐ変更に備えることができる。bitcoin.conf ファイルにユーザー名とパスワードを作成し、JSON-RPC コードを HTTP Basic 認証に対応するよう修正すればいい。古いコードは.conf ファイルと Authorization: HTTP ヘッダーを単に無視する。

皆に質問:HTTP Basic 認証の詳細な方法を wiki ページに追加すべきだろうか?PHP と Python では非常に簡単だ——http://user:pass@host:port/ の URL 構文を使うだけだ。HTTP Basic 認証の Wikipedia ページをただ複製したくはない。

ギャビン・アンドレセンの投稿(2010年7月23日 06:11 UTC)

皆に質問だ:HTTP Basic認証のやり方を詳しく説明するセクションをwikiページに追加すべきだろうか? PHPとPythonでは http://user:pass@host:port/ というURL構文を使うだけで非常に簡単にできる。

はい、各開発者が自分で調べなくて済むように、それは本当に良いと思う。Python、PHP、Java それぞれで json-rpc ライブラリをインポートして getinfo などを実行する簡単な例が必要だ。HTTP 認証部分も含めて。

ギャビンの変更は良さそうだ。すべて完了したと思う。テストビルドはこちらだ。テストしてくれ!

http://www.bitcoin.org/download/bitcoin-0.3.2.5-win32.zip http://www.bitcoin.org/download/bitcoin-0.3.2.5-linux.tar.gz

サトシ・ナカモトの投稿(2010年7月23日 08:07 UTC)

はい、各開発者が自分で調べなくて済むように、それは本当に良いと思う。Python、PHP、Java それぞれで json-rpc ライブラリをインポートして getinfo などを実行する簡単な例が必要だ。HTTP 認証部分も含めて。

分かった。Python と PHP は書いた。Java については知っている限りのことを追加した。Java JSON-RPC を使ったことのある人、動く例で wiki ページを更新してもらえないか?

lachesis 2010年7月23日 18:22 UTC 原文 ·

パスワードは絶対に必須にすべきではない。また、新しいコードは”rpcpassword=“で動作しなくなる。設定ファイルがない場合、設定ファイルに rpcpassword 行がない場合、または”rpcpassword=“が含まれている場合は、パスワードを無効にすべきだ。

lachesisの投稿(2010年7月23日 09:22 UTC)

パスワードは絶対に必須にすべきではない。

強く反対する。ソフトウェアはデフォルトで安全であるべきであり、パスワードなしで bitcoind を実行する(または bitcoin -server)のは明らかに安全ではない。

「設定ファイルにパスワードを追加しないとデーモンとして実行できないから Bitcoin はダメだ」と言う人はまずいないだろう。「うっかり -server スイッチを付けて実行したら誰かに全額盗まれたから Bitcoin はダメだ」と言う人は大いにあり得る。

conf ファイルがない場合や設定ファイルに rpcpassword が含まれていない場合に認証をデフォルトで無効にすべきではないと思うが、rpcpassword= を含む場合はどうだろうか?

両方の意見がわかる。

プログラマーが使用する言語(Fortran など)で HTTP 認証のやり方がわからない場合や、JSON-RPC ライブラリでサポートされていない場合はどうだろうか?パスワード要件を明示的に無効にできるようにすべきだろうか?

一方で、テンプレートの conf ファイルがあって、 rpcpassword= # ここにパスワードを入力 と書いてある場合はどうだろうか?

パスワードなしではログインできないシステムは多くある。例えばこのフォーラムがそうだ。ギャビンの意見の方が説得力がありそうだ。

ところで、テストはしていないが、conf ファイルに rpcpassword=があっても有効であることを願う。-server-daemon や bitcoind を使う場合のみ警告付きで失敗すべきだ。パスワードが不要な場合は問題ないはずだ。合っているか?

サトシ・ナカモトの投稿(2010年7月23日 20:39 UTC)

ところで、テストはしていないが、conf ファイルに rpcpassword=があっても有効であることを願う。-server-daemon や bitcoind を使う場合のみ警告付きで失敗すべきだ。パスワードが不要な場合は問題ないはずだ。合っているか?

そう、その通りだ。rpcpassword が必須なのは -server-daemon、bitcoind を使う場合だけだ(念のためたった今テストした)。

RE: プログラマが古い COBOL コードで HTTP 認証をどうやればいいか分からない場合は? それなら、「rpcpassword を空にしたら認証が切れる」というマジカルな仕様より、RPC 認証を明示的に切るための別の設定項目を conf ファイルに用意する方がいいと思う。ただ、誰かが実際に困るか、認証手段が複数になる(いつか https 対応とか)まではこれを実装するつもりはないね。

lachesis、HTTP Basic 認証に対応するのは君にとって問題かい?

lachesis 2010年7月24日 02:46 UTC 原文 ·

ギャビン、いや、問題ない。urllib2 の使い方はわかっているからな。bitcoin.conf でパスワード認証を無効化するオプションが欲しい。(上級)ユーザーを自分自身から守ろうとする必要はない。

ただイラついたのは、(テスト用クライアントとはいえ)-server を起動するためだけに、わざわざ config ファイルを編集してパスワードを入れなければならなかったことだ。もし望むなら、自分の Bitcoin をハックしてデフォルトでパスワード不要にすることはいつでもできる。でも、-server と一緒に rpcpassword= と書くと bitcoin が完全に起動失敗するのは気に入らない。正しいやり方は、ユーザーに警告(GUI 起動時ならポップアップなど)を出しつつ、たとえ RPC サーバーが起動しなくても他の機能は起動させることだと思う。

そもそもパスワード付きで動かしてもセキュリティ向上はわずかだ。多くのアプリでは、JSON-RPC コマンドを実行するためにそのパスワードを httpd が読めるファイルに置いておくしかないからな。私のサーバーでハックされたことのある唯一のユーザーは?httpd だ。とはいえ、複数ユーザーのマシンでは重要なステップだし、ポート番号を変更できるようにするのも同様だ。

lachesis 2010年7月25日 19:52 UTC 原文 ·

バグと思われるものを見つけた:ユーザー名とパスワードの組み合わせが十分長いと、bitcoind の Base64 エンコーダーが以下のような Authorization ヘッダーを生成する:

POST / HTTP/1.1
User-Agent: json-rpc/1.0
Host: 127.0.0.1
Content-Type: application/json
Content-Length: 40
Accept: application/json
Authorization: Basic YWJiYWJiYWFiYmE6aGVsbG93b3JsZGhlbGxvd29ybGRoZWxsb3dvcmxkaGVsbG93
b3JsZGhlbGxvd29ybGRoZWxsb3dvcmxk
64文字ごとに改行が挿入され、Authorizationヘッダーが壊れるため、「bitcoin getinfo」のようなコマンドが失敗する。サーバー側は正しく動作するクライアントからは問題なく動く。

Base64Encode 関数の末尾で result から改行(および’\r’)を除去すれば解決できる:

result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
result.erase(std::remove(result.begin(), result.end(), '\r'), result.end());
もっとエレガントな解決策があるかもしれないが、これで動く。パッチはこちら:
http://www.alloscomp.com/bitcoin/patches/bitcoin-svn-109-rpcbug-2010-07-25.patch
BitLex 2010年7月25日 20:45 UTC 原文 ·

こちらでも PHP で動かそうとして問題が出ている。 wiki のサンプル(jsonRPCClient で fopen(http://username:password@localhost:8332/)を試みる方法)も (http://username:password@localhost:8332/)%E3%82%92%E8%A9%A6%E3%81%BF%E3%82%8B%E6%96%B9%E6%B3%95%EF%BC%89%E3%82%82) curl のサンプル(setopt CURLOPT_HTTPAUTH, CURLAUTH_BASIC を使用)もうまくいかない。

The Madhatter 2010年7月25日 20:54 UTC 原文 ·

うーん……basic 認証ではなく digest 認証を使うべきではないか?

私は普段すべてを SSL か IPSec で包んでいるが、digest 認証なら初心者が簡単にやられるのを防げるかもしれない。😛

lachesis 2010年7月25日 21:00 UTC 原文 ·

ダイジェスト認証はクライアント側でもサーバー側でもかなり実装が難しい。_本来は_SSL とクライアント証明書を使うべきだが、それは本当に面倒だ。あるいは Unix ソケットか。

The Madhatter 2010年7月25日 21:05 UTC 原文 ·

うーん……10年ほど前に自作のウェブサーバーに digest 認証を実装したことがある。記憶では、実装はかなり簡単だった。ただ当時のクライアントサポートはかなり貧弱だった。それ以来大幅に改善されている。😊

stunnel + bitcoin のシンプルな設定を wiki に文書化するのはどうだろう?「Securely using bitcoind from remote」というセクションで。

いつものように 2 セントを提供するだけだ。😛

lachesisの投稿(2010年7月25日 10:52 UTC)

バグと思われるものを見つけた:ユーザー名とパスワードの組み合わせが十分長いと、bitcoindのBase64エンコーダーが以下のようなAuthorizationヘッダーを生成する:

Code:...
Authorization: Basic YWJiYWJiYWFiYmE6aGVsbG93b3JsZGhlbGxvd29ybGRoZWxsb3dvcmxkaGVsbG93
b3JsZGhlbGxvd29ybGRoZWxsb3dvcmxk

64文字ごとに改行が挿入されるため、Authorizationヘッダーが壊れ、“bitcoin getinfo”のようなコマンドが失敗する。サーバー自体は正しく動作するクライアントからは問題なく動作する。

これはBase64Encode関数の末尾で改行を除去すれば解決できる:

Code:result.erase(std::remove(result.begin(), result.end(), '
'), result.end());
result.erase(std::remove(result.begin(), result.end(), '
'), result.end());

このバグを見つけるほど長いパスワードを使っていたことに+1 だ。

SVN にリビジョン 110 としてアップロードした。

lachesisの投稿(2010年7月25日 10:52 UTC)

バグと思われるものを見つけた:ユーザー名とパスワードの組み合わせが十分長いと、bitcoindのBase64エンコーダーが以下のようなAuthorizationヘッダーを生成する:

素晴らしい発見だ!より簡単な修正は、rpc.cpp/EncodeBase64 関数で BIO_FLAGS_BASE64_NO_NL を指定することだ:

diff --git a/rpc.cpp b/rpc.cpp
index 72bdc50..703b757 100644
--- a/rpc.cpp
+++ b/rpc.cpp
@@ -765,13 +765,14 @@ string EncodeBase64(string s)
     BUF_MEM *bptr;
 
     b64 = BIO_new(BIO_f_base64());
+    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
     bmem = BIO_new(BIO_s_mem());
     b64 = BIO_push(b64, bmem);
     BIO_write(b64, s.c_str(), s.size());
     BIO_flush(b64);
     BIO_get_mem_ptr(b64, &bptr);
 
-    string result(bptr->data, bptr->length-1);
+    string result(bptr->data, bptr->length);
     BIO_free_all(b64);
 
     return result;
BitLexの投稿(2010年7月25日 11:45 UTC)

こちらでもPHPで動かそうとして問題が出ている。

おかしいな。誰かがそれでうまく動くと言っていなかったか?(彼はどのライブラリを使っていたのだろうか?)何が問題かわかったら投稿してくれ。

すべての PHP ユーザーにとってこれほど苦労することにならないことを願う。

Fortran のシナリオがもう実現してしまったようだな。

ギャビン・アンドレセンの投稿(2010年7月25日 12:38 UTC)

Great catch! Simpler fix is to specify the BIO_FLAGS_BASE64_NO_NL in the rpc.cpp/EncodeBase64 function

SVN リビジョン 111

lachesis 2010年7月25日 22:15 UTC 原文 ·
サトシ・ナカモトの投稿(2010年7月25日 21:44 UTC)

変だな、たしか誰かが動くはずだと言ってなかったか?(その人はどのライブラリを使ってた?)何が悪かったか分かったら投稿してくれ。

それは自分だ。http://jsonrpcphp.org/ のライブラリ(http://jsonrpcphp.org/download.php?file=tgz&package=light からダウンロード)を使っていて、これが動くことを確認できた。

<?php
require_once 'jsonRPCClient.php';
$bitcoin = new jsonRPCClient('http://username:password@localhost:8332/');
echo $bitcoin->getblockcount();
?>

このバグをこれほど早く直してくれた gavinandresen と satoshi に感謝する。

BitLex 2010年7月25日 22:41 UTC 原文 ·
lachesisの投稿(2010年7月25日 22:15 UTC)
サトシ・ナカモトの投稿(2010年7月25日 21:44 UTC)

変だな、たしか誰かが動くはずだと言ってなかったか?(その人はどのライブラリを使ってた?)何が悪かったか分かったら投稿してくれ。

それは自分だ。http://jsonrpcphp.org/ のライブラリ(http://jsonrpcphp.org/download.php?file=tgz&package=light からダウンロード)を使っていて、これが動くことを確認できた。 Code: require_once ‘jsonRPCClient.php’; $bitcoin = new jsonRPCClient(‘http://username:password@localhost:8332/’); echo $bitcoin->getblockcount(); ?>

自分の環境では動かない。wiki に載っていたから真っ先に試したんだが。 jsonRPCClient から返ってくるのはこれだけだ。 Warning: fopen(http://…@localhost:8332/ (http://...@localhost:8332/)) [function.fopen]: failed to open stream: HTTP request failed! HTTP/1.0 401 Authorization Required in …\jsonRPCClient.php on line 132

curl でもまだ認証を通せていない。返ってくるのは ..curl_error():transfer closed with 15 bytes remaining to read.. で、当然「bad json-syntax」になる。

php5.3.0 curl7.19.4 でテストしている。 何かアイデアがあれば歓迎する。

lachesis 2010年7月26日 00:26 UTC 原文 ·

まず、bitcoind getinfo は動くか?

次に、jsonrpcclient.php が送ろうとしているリクエストを netcat で捕まえてみてくれ(先にインストールが必要かもしれない)。

  1. bitcoind を停止
  2. netcat -l 8332
  3. ユーザー名とパスワードを(安全でないものに)変更してクライアントコードを実行
  4. netcat を Ctrl-C で止めて、出力を投稿してくれ