adiary置き換え計画始動から連なる、Lyndbaum v4.26アップデートの続き。
わずか二日でバージョンが0.8も増えた。直近で散々書いてきた、やることがなくなってきたとは一体何だったのか…。
今回は機能削除とセキュリティ対応、デグレード対応を主に行い、182ファイルの変更と4,659行の追加、4,585行の削除があった。
- セキュリティ対応
- パス・トラバーサル問題を修正
- ソケットが777で保存される問題を修正
- HTTPSでアクセスされたとき、CookieにSecure属性を付与するように修正
- セッションIDが予測可能だった問題を修正
- 有害なタグを使えないように修正
- lyndbaum.httpd.plを削除
- プライベートモードの削除
- 複数ユーザー機能の削除
- HTTPクライアントのHTTPS通信で証明書を検証するようにした
- ファイル名の変更で既存のファイルを上書きしないようにした
- HTTPS通信でタイムアウトするようにした
- アップロードしたファイルをリネームすることで本来上げられないファイル拡張子を上げることができた
- HTTPクライアントに制限をつけた
- SomeOrigin攻撃対策をした
- 検索操作時に任意コード実行の脆弱性があったのを修正
- check_user_dataの型チェックが常に偽になるのを修正
- ログインの失敗を同じIPからの回数でも数えるようにした
- その他
- 不具合対応
- 改善
- あとがき
セキュリティ対応
パス・トラバーサル問題を修正
特定の条件で..が指定されたときにCGIのルートフォルダなど本来アクセス出来てはならない場所を操作できる問題を修正した。
ソケットが777で保存される問題を修正
660にし、ユーザーとグループしか見れないようにした。
HTTPSでアクセスされたとき、CookieにSecure属性を付与するように修正
何も属性がついてなかったため。
セッションIDが予測可能だった問題を修正
rand()からPOSIXの乱数器に変更。
有害なタグを使えないように修正
管理者自身が自ら脆弱性を埋め込む可能性があるのを回避した。
これによってよく知らないスクリプトをコピペで記事などに埋め込んだ時に管理者が自滅するのを防止する。
lyndbaum.httpd.plを削除
nginxやApacheにさえ無限の脆弱性があるのにadiaryのhttpdに脆弱性がないはずがないと思って検査したところ無数の脆弱性が出てきたので削除した。
デバッグ用に残すことも検討したが、デバッグ時に脆弱性や不具合にぶつかったときに、その由来がhttpdか本体か区別できないため残さないことにした。
プライベートモードの削除
プライベートモードを突破できる脆弱性がいくつかあったため機能削除した。
プライベートにする場合、サーバー側で認証をかければ済む。
複数ユーザー機能の削除
管理者アカウントのみに限定し、ユーザー管理機能を丸ごと葬った。
これにより編集権限を持つユーザーが管理者やほかの編集ユーザーに攻撃可能になる脆弱性を作りこめてしまう問題など、アカウント機能があることで起こりえる問題が恒久的に消えた。
HTTPクライアントのHTTPS通信で証明書を検証するようにした
別にやらなくてもいいのだがやるようにした。
半年くらい前にQiitaが証明書違反になっているのを見かけたが、こういう場合は正規の通信先でもこけるようになるためOGP取得処理とかがこける。
ファイル名の変更で既存のファイルを上書きしないようにした
リネーム前に存在チェックをかけているため、これが起きることは現実的にはないのだが、原理上起きないようにした。
HTTPS通信でタイムアウトするようにした
今まではタイムアウトしなかったため相手から切られるか、OOMするまで放置されていた。
アップロードしたファイルをリネームすることで本来上げられないファイル拡張子を上げることができた
アップロード可能な拡張子を制限しているのにアップロード後にリネームすることでこの制約を抜けることができた。
これは次のケースで問題が起きることがある。ただし現実的にこれらが起きることはまずない。何故なら管理者の自爆操作だからだ。
- 悪意のあるスクリプトが仕込まれたHTMLを
.txtとしてアップロードし、その後.htmlに書き換えて開くことで同一オリジン攻撃が可能になり、管理権限を乗っ取れる - 悪意のあるスクリプトが仕込まれたPHPを
.txtとしてアップロードし、その後.phpに書き換えて開くことで任意コードが実行可能になる
書いていて思ったこととして、アップロードできる拡張子の制限という機能そのものをなくしたほうがいい気がしてきた。こんなことをしても無駄な処理とテストが増えるだけなので。
HTTPクライアントに制限をつけた
内部向けのアクセスができないようにし、巨大なファイルをダウンロードしようとしたら止めるようにした。
間違えて内部にいるPrometheusのような管理ツールのOGPを記事に展開しようとしてもできなくなった。
IPv4向けの対応であり、v6向けには特に何もしていない。
SomeOrigin攻撃対策をした
レンタルサーバーでは*.sakura.ne.jpや*.x0.toなど、サブドメインが異なる他人が多くいるため、HTTPヘッダーを検証し、同一オリジン以外からのCSRF攻撃が起きないようにした、
検索操作時に任意コード実行の脆弱性があったのを修正
このブログには付けていないが、特定の検索機能で任意コードが実行可能だったので対応した。
check_user_dataの型チェックが常に偽になるのを修正
動作的には特に問題がなかったがバグではあるため直した。
ログインの失敗を同じIPからの回数でも数えるようにした
IDに対して行っていると管理者のIDに対してログイン失敗を繰り返すことで管理者を締め出せるため、IPでも見るようにした。
その他
- HTTP(S)通信で無限リダイレクトしないようにした
- メールの送信でタイムアウトするようにした
- wwwのプロセスのumaskを0から002にする
- indexを一時ファイルに書いてからrenameで置き換え、ロックの後に置き換わっていないか確かめる
- 空のindexを作り直し、ファイルの書き込みのエラーを返す
- pkeyを指定したinsertのシリアル値を、indexと一緒に保存する
- ソケットのパーミッションを変更
- その他セキュリティ修正をいくつか追加
不具合対応
ファイル名によってアップロード後の操作ができない問題を修正
ファイル操作によってファイル名の検査処理が異なりエラーになっていたのを直した。
その他
- JSONパーサーが正しくJSONをパース出来ていなかった問題の修正
- 途中で切れたテンプレートのキャッシュでページがエラーのままになっていたのを修正
- テキストDBの検索の値を埋め込んだ関数を際限なく保持していたので、1000個を超えたら捨てるようにした
- OOMが起きる可能性があった
- ページキャッシュ機能で同じ秒に同じ大きさで書き直されたファイルの古い内容を出し続けることがあったのを修正
- 現実問題ほぼほぼ起きないと思うが一応対応した
改善
メインカラムが<div />だったのを<main />に変更
Webアクセシビリティ対応。
自動テストの高速化
11ファイル、1,475件、108秒を分割し、テストを並行で走行するようにした。結果、14ファイル、1,476件、26秒に短縮した。1件増えてるのは分割したせい。
機能削除の繰り返しにより最新版では22ファイル、1,290件、20秒にまで減っている。
env.cgiとconf.cgiを統一し、設定を全体的に見直した
分けている意味が分からないため統一した。
また設定の持ち方がカオスだったのを見直し、大半の設定を画面からできるようにし、致命的なケース以外では設定ファイルをいじくらなくていいようにした。
アイキャッチの自動設定機能を廃止
アイキャッチを編集画面で選んだ画像だけにし、自動設定機能を外した。
これはフロントエンドの表示とサーバーサイド側の処理で判定が異なり、画面上の表示と実際の処理が異なっていたほか、コードフェンスの中に画像のパスがあると、それを取り込んでしまうなど問題が色々あって対応が面倒だったのでやめた。
ユーザーが選べば解決するなら凝った実装を排除したほうがいい。ユーザーの手間が3秒増える程度。どうせ選びたいときは選ぶわけだし。
ページトップのOGPを無条件で出すようにした
v0.5.0でOGPの出力条件を削除し、UserAgentに依存させないようにしたの対応漏れ。
ついでにTwitter向けのOGPのサイズをデフォルト画像とそれ以外で可変にする対応を入れているが、私はTwitterをしていないため動作確認してない。
v4.29/v4.33より古いデータからのアップデートサポートを切り捨て
後方互換性維持のために残していた負債実装をすべて削除した。
adiary v3.52devからアップデートする場合、一度v4.29をチェックアウトし、バージョンアップしたのち、次にv4.33をチェックアウトしアップデートし、その後v4.34をチェックアウトしてアップデートすることでアップデート可能。
v4.34時点のコミットをチェックアウトするとアップデート処理が消滅しているので、段階的に作業する必要がある。
マルチサイト削除対応で残った残骸を除去
この対応によりv4.29/v4.33以前との互換性が完全に消滅した。
あとがき
今回のコードの変更量はバージョンのわりに少ないがClaudeを使って何回も多角的に調査させたため、木曜の今時点でMax x5プランで28%も使ってしまった。
Fable 5.1も使ってみたが的外れな指摘が多く役に立たず、役に立った指摘はOpus 5.5からのものだった。また、現時点でChatGPTの契約がまだ生きているのでGPT-6.1 Solにも見させているが、GPT-6.1 Solの指摘はClaudeとは全く違う視点から来ているのにクロスチェックに便利だと感じた。但し指摘が的外れであることも少なくなく、有用性としては補助程度に留まった。
ChatGPTの功績を残したのでGitHubの貢献者にCodexを生やすことができた。Codexはv4.27のHTTP通信のタイムアウトをスレッドごとに制御するを担当した。なお私はCodexをほとんど信頼してないのでこれしかやらせていない。
しかしまぁここ一ヶ月のコミットは本当にすごいことになっているのでコーディングエージェントの凄さを痛感する。
前も書いた気がするが去年まではLLMはハルシネーションの塊だと思っていたし、半年前でもまだ私のほうが上だと思っていたのに、もはや太刀打ちできない。私がやっているのはPRを手書きし、この記事を書くことでコードレビューを多少なりとも行い、気になった部分を観たり、わからなければLLMに確認する程度だ。
GitHubの草も珍しく列が繋がりそうになった。
縦に繋がったことは過去に一度しかなく、2021年初頭の話なので、もし繋がったら五年半ぶりの快挙になる。