特定の条件で..が指定されたときにCGIのルートフォルダなど本来アクセス出来てはならない場所を操作できる問題を修正した。
660にし、ユーザーとグループしか見れないようにした。
何も属性がついてなかったため。
rand()からPOSIXの乱数器に変更。
管理者自身が自ら脆弱性を埋め込む可能性があるのを回避した。
これによってよく知らないスクリプトをコピペで記事などに埋め込んだ時に管理者が自滅するのを防止する。
nginxやApacheにさえ無限の脆弱性があるのにadiaryのhttpdに脆弱性がないはずがないと思って検査したところ無数の脆弱性が出てきたので削除した。
デバッグ用に残すことも検討したが、デバッグ時に脆弱性や不具合にぶつかったときに、その由来がhttpdか本体か区別できないため残さないことにした。
プライベートモードを突破できる脆弱性がいくつかあったため機能削除した。
プライベートにする場合、サーバー側で認証をかければ済む。
管理者アカウントのみに限定し、ユーザー管理機能を丸ごと葬った。
これにより編集権限を持つユーザーが管理者やほかの編集ユーザーに攻撃可能になる脆弱性を作りこめてしまう問題など、アカウント機能があることで起こりえる問題が恒久的に消えた。
別にやらなくてもいいのだがやるようにした。
半年くらい前にQiitaが証明書違反になっているのを見かけたが、こういう場合は正規の通信先でもこけるようになるためOGP取得処理とかがこける。
リネーム前に存在チェックをかけているため、これが起きることは現実的にはないのだが、原理上起きないようにした。
今まではタイムアウトしなかったため相手から切られるか、OOMするまで放置されていた。
アップロード可能な拡張子を制限しているのにアップロード後にリネームすることでこの制約を抜けることができた。
これは次のケースで問題が起きることがある。ただし現実的にこれらが起きることはまずない。何故なら管理者の自爆操作だからだ。
- 悪意のあるスクリプトが仕込まれたHTMLを
.txtとしてアップロードし、その後.htmlに書き換えて開くことで同一オリジン攻撃が可能になり、管理権限を乗っ取れる
- 悪意のあるスクリプトが仕込まれたPHPを
.txtとしてアップロードし、その後.phpに書き換えて開くことで任意コードが実行可能になる
書いていて思ったこととして、アップロードできる拡張子の制限という機能そのものをなくしたほうがいい気がしてきた。こんなことをしても無駄な処理とテストが増えるだけなので。
内部向けのアクセスができないようにし、巨大なファイルをダウンロードしようとしたら止めるようにした。
間違えて内部にいるPrometheusのような管理ツールのOGPを記事に展開しようとしてもできなくなった。
IPv4向けの対応であり、v6向けには特に何もしていない。
v6にして行うと自宅サーバーで自分がホストする別のサービスに繋げなくなるため、v6に対して行う予定は今のところない。
レンタルサーバーでは*.sakura.ne.jpや*.x0.toなど、サブドメインが異なる他人が多くいるため、HTTPヘッダーを検証し、同一オリジン以外からのCSRF攻撃が起きないようにした、
このブログには付けていないが、特定の検索機能で任意コードが実行可能だったので対応した。
動作的には特に問題がなかったがバグではあるため直した。
IDに対して行っていると管理者のIDに対してログイン失敗を繰り返すことで管理者を締め出せるため、IPでも見るようにした。
- HTTP(S)通信で無限リダイレクトしないようにした
- メールの送信でタイムアウトするようにした
- wwwのプロセスのumaskを0から002にする
- indexを一時ファイルに書いてからrenameで置き換え、ロックの後に置き換わっていないか確かめる
- 空のindexを作り直し、ファイルの書き込みのエラーを返す
- pkeyを指定したinsertのシリアル値を、indexと一緒に保存する
- ソケットのパーミッションを変更
- その他セキュリティ修正をいくつか追加
ファイル操作によってファイル名の検査処理が異なりエラーになっていたのを直した。
- JSONパーサーが正しくJSONをパース出来ていなかった問題の修正
- 途中で切れたテンプレートのキャッシュでページがエラーのままになっていたのを修正
- テキストDBの検索の値を埋め込んだ関数を際限なく保持していたので、1000個を超えたら捨てるようにした
- ページキャッシュ機能で同じ秒に同じ大きさで書き直されたファイルの古い内容を出し続けることがあったのを修正
Webアクセシビリティ対応。
11ファイル、1,475件、108秒を分割し、テストを並行で走行するようにした。結果、14ファイル、1,476件、26秒に短縮した。1件増えてるのは分割したせい。
機能削除の繰り返しにより最新版では22ファイル、1,290件、20秒にまで減っている。
分けている意味が分からないため統一した。
また設定の持ち方がカオスだったのを見直し、大半の設定を画面からできるようにし、致命的なケース以外では設定ファイルをいじくらなくていいようにした。
アイキャッチを編集画面で選んだ画像だけにし、自動設定機能を外した。
これはフロントエンドの表示とサーバーサイド側の処理で判定が異なり、画面上の表示と実際の処理が異なっていたほか、コードフェンスの中に画像のパスがあると、それを取り込んでしまうなど問題が色々あって対応が面倒だったのでやめた。
ユーザーが選べば解決するなら凝った実装を排除したほうがいい。ユーザーの手間が3秒増える程度。どうせ選びたいときは選ぶわけだし。
v0.5.0でOGPの出力条件を削除し、UserAgentに依存させないようにしたの対応漏れ。
ついでにTwitter向けのOGPのサイズをデフォルト画像とそれ以外で可変にする対応を入れているが、私はTwitterをしていないため動作確認してない。
後方互換性維持のために残していた負債実装をすべて削除した。
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年初頭の話なので、もし繋がったら五年半ぶりの快挙になる。