JSON-RPCパスワード

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

-serverスイッチは-rpcpw=に置き換えられ、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ファイルは次のようになる: Code:{ “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ベーシック認証には追加のメリットがあるか?パラメータリストから移動しても、より難解な場所で指定する必要があるのでは、純粋な改善とは言えないかもしれない。

Quote from: gavinandresen on July 19, 2010, 12:02:39 PM

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

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

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

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

Quote from: satoshi on July 19, 2010, 04:20:50 PM

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

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

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

Quote from: gavinandresen on July 19, 2010, 12:02:39 PM

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

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

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

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

Code:> bitcoind help error: First parameter must be the password.

bitcoind help error: unknown command: bitcoind help … that works.

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

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

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

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

# コメント
setting=value

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

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

Gavinに指摘されたが、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日 原文 · 個別ページ

最もシンプルな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

Quote from: gavinandresen on July 21, 2010, 12:11:10 PM

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

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

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

私の推しは:

# comment
key1=value1

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」形式を持っている。Gavinが指摘したように、型付き値抽出のような難解な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日 原文 · 個別ページ

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

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

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

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

Quote from: gavinandresen on July 22, 2010, 01:11:26 AM

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

完了: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を実行しやすくなる。

この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ページをただ複製したくはない。

Quote from: gavinandresen on July 23, 2010, 03:11:45 PM

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ページをただ複製したくはない。

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

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

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

Quote from: satoshi on July 23, 2010, 05:07:40 PM

Quote from: gavinandresen on July 23, 2010, 03:11:45 PM

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ページをただ複製したくはない。

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

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

lachesis 2010年7月23日 原文 · 個別ページ

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

Quote from: lachesis on July 23, 2010, 06:22:08 PM

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

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

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

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

両方の意見がわかる。

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

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

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

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

lachesis 2010年7月25日 原文 · 個別ページ

バグと思われるものを見つけた:ユーザー名とパスワードの組み合わせが十分長いと、bitcoindのBase64エンコーダーが以下のようなAuthorizationヘッダーを生成する: Code: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’)を除去すれば解決できる: Code: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日 原文 · 個別ページ

こちらでもPHPで動かそうとして問題が出ている。 wikiのサンプル(jsonRPCClientでfopen(http://username:password@localhost:8332/)を試みる方法)もcurlのサンプル(setopt CURLOPT_HTTPAUTH, CURLAUTH_BASICを使用)もうまくいかない。

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

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

lachesis 2010年7月25日 原文 · 個別ページ

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

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

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

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

Quote from: lachesis on July 25, 2010, 07:52:35 PM

バグと思われるものを見つけた:ユーザー名とパスワードの組み合わせが十分長いと、bitcoindのBase64エンコーダーが以下のようなAuthorizationヘッダーを生成する: Code: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’)を除去すれば解決できる: Code: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

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

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

Quote from: lachesis on July 25, 2010, 07:52:35 PM

バグと思われるものを見つけた:ユーザー名とパスワードの組み合わせが十分長いと、bitcoindのBase64エンコーダーが以下のようなAuthorizationヘッダーを生成する: Code: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’)を除去すれば解決できる: Code: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

素晴らしい発見だ!より簡単な修正は、rpc.cpp/EncodeBase64関数でBIO_FLAGS_BASE64_NO_NLを指定することだ: Code: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;

Quote from: BitLex on July 25, 2010, 08:45:38 PM

こちらでもPHPで動かそうとして問題が出ている。 wikiのサンプル(jsonRPCClientでfopen(http://username:password@localhost:8332/)を試みる方法)もcurlのサンプル(setopt CURLOPT_HTTPAUTH, CURLAUTH_BASICを使用)もうまくいかない。

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

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

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

Quote from: gavinandresen on July 25, 2010, 09:38:19 PM

Quote from: lachesis on July 25, 2010, 07:52:35 PM

バグと思われるものを見つけた:ユーザー名とパスワードの組み合わせが十分長いと、bitcoindのBase64エンコーダーが以下のようなAuthorizationヘッダーを生成する: Code: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’)を除去すれば解決できる: Code: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

素晴らしい発見だ!より簡単な修正は、rpc.cpp/EncodeBase64関数でBIO_FLAGS_BASE64_NO_NLを指定することだ: Code: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;

SVN リビジョン 111