fix(base): refuse to send credentials over a non-HTTPS endpoint

オープン
#307 コメント 0 件 リアクション 0 件 担当者 1 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@ffumero2003 がすでに取り組んでいます。

2026年11月8日 から。

評価

この issue はまだ評価されていません。

説明

bug

Context

b2.APIBase / base.SetAPIBase accept any URL string, and b2_authorize_account sends the application key as Authorization: Basic ... to it (base/base.go), which is the actual secret on the wire, not a derived signature. No scheme check exists, so a misconfigured non-loopback http:// endpoint sends the key, and later tokens, in cleartext.

Decision: refuse non-HTTPS, no opt-out (resolved)

Allow HTTPS, allow loopback-IP-literal HTTP for local testing, refuse everything else — including localhost and private-network http — with a clear error. No opt-out flag. Rationale, from blazer and the B2 reference SDKs:

  • blazer already treats a broken transport as permanent: TLS certificate failures are not retried and there is no skip-verify escape hatch (base/base.go:555). Refusing plaintext credentials is consistent with that posture.
  • The B2 TypeScript SDK (the newest) solves exactly this with no opt-out: assertSecureRealmUrl (src/auth/realms.ts) allows HTTPS or loopback-IP HTTP and throws refusing to send credentials over plaintext HTTP realm for anything else.
  • It deliberately excludes localhost from loopback: "it is resolver-controlled, while [IP literals are not]." Loopback is therefore 127.0.0.1 and ::1 only.
  • The B2 Java SDK's setSupportInsecureHttp is off by default and documented as test-only ("that's a good way to leave it").
  • B2 sends the key as HTTP Basic, unlike S3 SigV4 where the secret never travels, so an easy opt-out would cleartext a long-lived master key — exactly the footgun to avoid. If a real internal-HTTPS-less endpoint need appears later, an opt-out can be added as a non-breaking minor feature.

Behavior change: needs a **Breaking:** changelog entry and an /sdk-panel-review pass.

Acceptance criteria

  • R1. Red: a non-loopback http:// endpoint is currently accepted and the credential is sent.
  • R2. Green: a non-loopback http:// endpoint is refused before any credential is sent, with a clear error naming the endpoint; https:// works; loopback-IP http:// (127.0.0.1, ::1) works.
  • R3. localhost over http:// is refused (resolver-controlled, not a loopback IP literal). No existing test depends on http://localhost; the wire tests use httptest, whose URL is http://127.0.0.1:PORT.
  • R4. The ~87 tests that reach a server through APIBase/SetAPIBase with a loopback-IP httptest URL still pass.
  • R5. The check covers both the initial authorize and a restored-session API URL (a persisted AccountInfo whose apiUrl is non-loopback http), so a cleartext URL cannot slip in through session restore.

In scope

  • Refuse to attach credentials when the endpoint scheme is not https and the host is not a loopback IP literal (127.0.0.1, ::1). Apply at b2_authorize_account and to a restored-session API URL.
  • A clear, non-retryable error that names the offending endpoint and does not leak the credential.

Out of scope

  • An opt-out flag for non-HTTPS endpoints (decided against above; revisit only on real demand, as a non-breaking addition).
  • Accepting http://localhost (excluded deliberately).
  • Any change to upload/download URL handling that B2 itself returns over HTTPS, beyond the restored-session API URL check in R5.
  • Unrelated work outside the components and behavior described in In scope.

Verification

Run the repository regression checks with live credentials unset:

unset B2_APPLICATION_KEY_ID B2_APPLICATION_KEY B2_ACCOUNT_ID B2_ACCOUNT_KEY
go build ./...
go vet ./...
go test -race -count=1 ./base ./b2/...
  • Red first: show a non-loopback http:// endpoint is accepted and the credential is sent today. After the fix, show it is refused with the stated error before any request carries the key.
  • Cover both the authorize path and a restored-session API URL (R5), using synthetic credentials.
  • Show https:// and loopback-IP http:// still work, and http://localhost is refused (R3). Retain the existing loopback-IP test coverage (R4).
  • Record the **Breaking:** changelog entry and run the SDK panel review on the diff.
  • Expected result: the checks above succeed and the observable outcomes in Acceptance criteria are demonstrated. If a check cannot run, report Could not run because: ...; if it starts but fails, report Could not complete because: .... A skipped check is not a pass.

Links

主要言語
Go
スター
66
フォーク
18
平均マージ
1日 10時間
マージ済み PR(30日)
132

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

Backblaze/blazer のほかの issue

Backblaze/blazer の issue をすべて見る

似ている issue

Go の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。