JSON-RPCパスワード

14 件のメッセージ サトシ・ナカモト 2010年7月18日 — 2010年7月25日

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

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

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

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

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

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

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

Quote from: gavinandresen on July 19, 2010, 12:02:39 PMパスワードがコマンドラインでは最後に指定されるのに、JSON-RPCのパラメータリストでは最初に来るので、少し混乱しました。コマンドラインのパスワードをファイルから読み取る方が便利で安全だという意見に同意します。 あなたにも混乱させられている。どういう意味だ?何か意図しない動作があったのか?

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

Quote from: gavinandresen on July 21, 2010, 12:11:10 PMDebianシステムの/etc内の20個の.confファイルを簡単に調査したところ: 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ベーシック認証で進めよう。

Quote from: gavinandresen on July 22, 2010, 01:11:26 AMTODO: rpc.user/rpc.passwordが設定されていない場合、設定方法を説明するダイアログボックスまたはdebug.logの警告。 この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

Quote from: gavinandresen on July 23, 2010, 03:11:45 PM皆さんへの質問: HTTPベーシック認証の詳細なやり方を説明するセクションをWikiページに追加すべきでしょうか?PHPとPythonでは本当に簡単です — http://user:pass@host:port/ のURL構文を使うだけです。 はい、各開発者が自分で調べなくて済むように、それは本当に良いと思う。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

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

両方の意見がわかる。

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

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

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

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

Quote from: lachesis on July 25, 2010, 07:52:35 PMバグと思われるものを見つけました: ユーザー名とパスワードの組み合わせが十分に長い場合、bitcoindのBase64エンコーダーが以下のようなAuthorizationヘッダーを生成します: Code:… Authorization: Basic YWJiYWJiYWFiYmE6aGVsbG93b3JsZGhlbGxvd29ybGRoZWxsb3dvcmxkaGVsbG93 b3JsZGhlbGxvd29ybGRoZWxsb3dvcmxk 64文字ごとに改行が挿入され、明らかにAuthorizationヘッダーが壊れるため、「bitcoin getinfo」のようなコマンドが失敗します。サーバーは正しく動作するクライアントでは問題なく動作します。

これはBase64Encode関数の結果から改行(およびおそらく”)を削除することで解決できます:

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

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

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

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素晴らしい発見です!より簡単な修正は、rpc.cpp/EncodeBase64関数でBIO_FLAGS_BASE64_NO_NLを指定することです。 SVN リビジョン 111