要約
- 新しい試験はバッファーを1バイトに設定して一時ファイル経路を強制し、Wicketの
FileUpload.getBytes()が入力と同じバイト列を返すことを確かめる。 organizations.xlsxの中身は短いUTF-8文字列で、carta-ce.pdfもPDFヘッダーとコメントだけであり、OOXMLや完全なPDFは解析されない。- 高速な転送試験は残しつつ、実形式、選挙固有の規則、認可、サイズと展開量を別々の受領証として結び付けるべきだ。
試験名と観測事実の距離
2026年9月11日、LACNICの公開リポジトリelections-open-sourceにwicketFileUploadGetBytesWorksForDiskBackedExcelAndPdfというメソッドが追加された。名前だけ読めば、ディスク保存されたExcelとPDFのアップロードが一通り動くことを示すように見える。実装が観測する範囲はもっと狭く、その狭さこそ診断上の価値である。
試験はDiskFileItemFactoryを作り、JUnitの一時ディレクトリを設定し、バッファーサイズを1にする。空でない二つの標本は閾値を超え、メモリーだけでなく一時ファイルに置かれる。補助メソッドはバイトを書き込み、その項目をWicketのFileUploadで包み、getBytes()を呼び、返り値を元の配列と完全比較する。最後はfinallyで一時項目を削除する。
Commons FileUploadは閾値に応じて小さい項目をメモリーに残し、大きい項目をディスクへ移す。依存関係の更新後、メモリー経路だけが正常で、ディスク上の項目をWicketが読めない可能性は理論上分離できる。閾値を1にすることで、小さく読みやすい標本でも対象の分岐を必ず通る。この設計は回帰試験として合理的だ。
一方、変数spreadsheetはORGID、改行、ALFA-001という文字列にすぎない。本物の.xlsxはZIPを基盤にしたOOXMLパッケージで、内容型、関係、ワークシート、XML部品を持つ。変数pdfは%PDF-1.1、改行、%carta、改行だけで終わる。先頭署名はあるが、PDFのオブジェクト、相互参照、終端構造はない。
補助メソッドはそれぞれにorganizations.xlsxとcarta-ce.pdfという名前を与える。しかしXSSFWorkbookもPDFパーサーも呼ばない。クライアントファイル名は利用者が付けるラベルであり、MIME型も入口で申告されることが多い。形式とは内部構造である。ラベルと構造を同一視すると、試験結果が実験より広い約束になる。
正確な結論は明快だ。構成されたディスク保存項目から、Wicketは書き込まれたものと同じバイトを返した。文書が開けること、必須列があること、操作者に権限があること、選挙データが正しく変わることは結論に含まれない。これは試験を弱める限定ではなく、将来も再利用できる証拠にする限定である。
実際の経路には別の検証がある
新しいメソッドだけから「LACNICは拡張子しか見ていない」と結論するのも誤りだ。同じ試験クラスには、文字列をphoto.jpgと名付けて候補者写真バリデーターへ渡し、無効形式として拒否されることを確認する例がある。別の例は実際の800×600 PNGを生成し、JPEGへ処理し、再び読み込み、幅と高さが400以下であることを確かめる。
画像の場合、内容はデコーダーに理解され、変換後の条件も満たさなければならない。ここには「読めたバイト」から「意味のある画像」への段差が見える。転送標本が合成文字列でよいことと、形式標本が本物でなければならないことは両立する。
組織一覧のアップロードも、入口の名前判定で終わらない。OrganizationExcelFileValidatorは、名前が.xlsxで終わるか、申告されたMIME型がOOXML表計算形式なら次へ進める。このOR条件はクライアント由来の信号を使う予備選別である。債務組織と削除ではバイトがリモート検証へ送られ、追加と更新では送信時に詳細検証が行われる。
ExcelUtilsはバイトを一時ファイルへ書き、OOXMLのMIME型を要求し、Apache POIのXSSFWorkbookを構築する。最初のシートを選び、見出しを解析し、行を処理する。債務組織一覧にはORGIDが必要で、追加・更新にはさらに多くの列が必要だ。空の識別子、重複、欠落した列、不正値は業務に対応したエラーとなる。
組織管理パネルは、変更をキューへ入れる前に操作ごとの適用可能性も調べる。既に処理中なら二つ目の作業を作らない。したがって、短いORGID\nALFA-001はバイト試験には合格し、実際のXSSFWorkbookには失敗できる。前者は受け渡し、後者は文書構造、その後は選挙ルールを守る。結果は矛盾しない。
有権者名簿も同じように段階化される。パネルはWicketのアップロードからバイトを得て、対象選挙へ更新を適用できるか検証し、その後にだけキュー投入を試みる。新試験が再現するのはバイト取得の形であって、名簿の列、行、選挙状態、最終効果ではない。
結果通知書には異なる統制がある。multipartフォーム全体には10MBの上限がある。保存時、ページは対象選挙を読み直してアクセスを強制し、選挙が終了済みなら中止する。スペイン語、英語、ポルトガル語の任意通知書を検証し、すべての判断が通った後で選択されたバイトを管理者とクライアントアドレスの文脈付きで保存する。
ただしElectionResultLetterSupport.isPdfが見るのは最初の4バイト%PDFだけである。短い標本はこの条件に通るが、表示可能で整合したPDFである証明にはならない。10MB上限、権限、終了状態、監査文脈は実在する統制であり、それでも文書構造の検証とは別物だ。
一つの緑丸を五枚の受領証へ分ける
「アップロードは動く」という表現は、境界も失敗の影響も示さない。受入証拠を五つに分けると、観測と判断が追跡可能になる。
第一は転送受領証である。メモリーとディスクの両方を通し、対象ケースでisInMemory() == falseを明示的に確認し、バイト比較、ストリーム終了、一時項目の削除を調べる。今回の試験は良い核だ。名称を「ディスク保存FileUploadのgetBytesがバイト同一性を保つ」とすれば、ファイル名は用途例のまま、パーサーの権威を借りない。
第二は形式受領証である。OOXMLなら、POIなどで生成した小さな本物のワークブックに必要シートと見出しを入れる。通常のZIP、途中で切れたパッケージ、方針に応じた暗号化文書も負例にする。PDFなら、採用したパーサーが受け入れる完全な最小文書、ヘッダーだけのデータ、切断ファイル、関連する偽装例を用意する。拡張子、MIME、署名は組み合わせる信号であり、構造の代役ではない。
第三は業務受領証である。本物のワークブックを組織または名簿のバリデーターへ入れ、読取不能、列欠落、空行、重複ORGID、不正な国や票数を区別する。エラーレポートが正しい行を示すか、拒否入力がキュー作業を残さないかも確かめる。選挙固有条件は既知の初期状態と期待結果を持たなければならない。
第四は手続受領証である。権限を持つ管理者は開いている選挙を操作でき、権限のないセッションと終了済み選挙は拒否される。有効な入力は一つの作業だけを作り、監査文脈と永続的な結果が期待に一致する。同時送信は「処理中」の保護に当たる。三言語の通知書では、一つの不正ファイルがあれば、どの変更も適用する前に止める。
第五は資源受領証である。要求サイズ、メモリー、一時保存場所、削除、解析時間、圧縮展開量を測る。Commons FileUploadは閾値と要求上限を説明している。Apache POIは、外部文書の解析ではライブラリだけで全ての有害な作用を防げず、追加の保護や分離が必要だとする。ZipSecureFileは圧縮比や展開後エントリーサイズの制限を提供する。
OWASPも、認可、許可拡張子、MIME、署名、ファイルサイズ、解凍後サイズを重ねるよう勧める。これはLACNICの脆弱性を示す資料ではない。一般的な防御原則を、受入記録が答えるべき問いへ変換するための資料である。
公開コードと本番事実を混同しない
固定した管理モジュールPOMはWicket 10.9.0を宣言し、WildFlyモジュールはPOI OOXML 5.0.0を参照する。これらは読んだコミットの構成を記録するが、実際の選挙環境が同じバージョン、設定、ディレクトリを使う証拠ではない。
依存関係の更新と回帰試験が近い時刻に現れても、更新が障害を引き起こしたとは言えない。保守者が先回りして境界を固定した可能性もある。事故、侵害、データ消失、選挙操作を示す資料はなく、そのような主張をコードから作ってはならない。
PDFの4バイト判定も、直ちに欠陥と呼ぶべきではない。それが意図的な予備判定か、十分条件として採用された方針かは、公開コードだけでは決められない。通知書の提供者、保存と配布の仕方、互換性との取引条件によって必要な深さは変わる。ここで言えるのは、実装が完全なPDF構造を解析していないという観測だけだ。
小さい試験は、失敗箇所を狭くする
全要素を一つの巨大な結合試験にすれば安心が増えるとは限らない。Wicket、ディスク、POI、選挙データ、認可、キュー、永続化が同時に関わると、赤い結果の原因がぼやける。速い転送試験はパーサーより前の境界を単独で監視する。それが存在する価値は大きい。
改善対象は試験そのものより、組織が覚える要約である。リリース審査や監査では、実装より試験名が引用される。「ディスク上のExcelとPDFが動く」は短く、伝わりやすく、実験より広い。「ディスク保存されたバイトをWicketが同一に返す」は地味だが、赤くなったとき誰が何を調べるべきか正確に示す。
試験データも分けて管理できる。転送標本は小さく透明に保つ。実文書標本は生成方法とバージョンを持つ。業務用ワークブックは既知の行と期待結果を持つ。一つの巨大バイナリーに全てを背負わせるより、最小で本物の標本を各層に置く方が、速度と保守性と説明力を同時に守れる。
本物の文書にも来歴が必要だ
短い文字列を実際のワークブックへ置き換えるだけでは証拠は完成しない。生成方法の分からないバイナリーは、数年後に「以前は開けたファイル」という黒箱になる。どのツールと版が作ったか、なぜその列を持つか、どの異常が意図的かが分からなければ、依存関係の更新で差が出たときに説明できない。テスト内で最小OOXMLを生成するか、生成手順、要約、期待するシート構造を一緒に保存する方がよい。
PDF標本にも同じ原則が当てはまる。完全な最小文書は、何ページあり、選択したパーサーが何を読み、外部参照や埋め込み要素をどう扱うかを明示すべきだ。「PDFではない」「PDFだが途中で切れている」「構造は読めるが結果通知書の方針に合わない」は異なる失敗である。一つの無効形式メッセージにまとめると、管理者も利用者も修正点を判断しにくい。
深い形式検証には互換性との取引がある。緩すぎれば用途外の内容が保存され、厳しすぎれば正当だが珍しい生成器の文書を拒否する。一般的なガイドがLACNIC向けの唯一解を決めるわけではない。結果通知書はダウンロードできればよいのか、指定パーサーで開ける必要があるのか。暗号化、添付、スクリプト、大きなページを許すのか。拒否するか隔離審査へ送るか。これらは明文化すべき製品判断である。
三言語通知書では原子性が主役になる
結果画面はスペイン語、英語、ポルトガル語の三ファイルを一度に扱う。コードが三件を先に検証し、その後に適用する順序は重要だ。最も意味のある負例は、二件が有効で一件が無効なとき、どれも部分更新されないことだ。既存通知書の削除、新規ファイルがない場合の保持、削除と置換の組合せも、画面上の意図と保存結果が一致するか確認したい。
検証後の保存失敗も別の境界である。利用者へ何を返すか、旧ファイルは利用可能なままか、監査記録は何を示すか。公開コードでは保存呼出しに管理者とクライアントアドレスの文脈が渡るが、互換性試験はそこへ到達しない。「文書が有効」と「操作が完了した」を分ける手続受領証が必要になる。
組織一覧の非同期処理には別の時間軸がある。検証成功、キュー投入成功、処理進行、最終的な作成・更新・削除件数は同じ出来事ではない。キューが競合で拒否されたとき、ファイル不正として表示してはならない。各段階に期待状態を持たせれば、形式失敗、業務拒否、同時実行、実行時失敗を区別できる。
制限は置かれた場所まで記録する
10MB上限は結果通知書フォームで確認できる事実だが、組織や名簿の画面へ自動的に外挿できない。フレームワーク全体やプロキシに別の既定値があるかもしれないが、確認していないものを保証として書くべきではない。POIに圧縮対策があることも、アプリケーションが特定値を設定した証明にはならない。どの層で制限し、どの層で試験し、超過時に誰が応答するかを受領証へ記す必要がある。
getBytes()は完全な配列を返す。アップロード時に一度ディスクへ置かれても、呼出し時には全内容をメモリーへ載せる可能性がある。ストリームAPIが存在するからといって、現在のバリデーターやリモート呼出しをそのまま置換できるわけではない。将来変更するなら、byte[]を前提にする解析・保存境界を調べ、入力上限、別プロセス解析、ストリーム化のどれを選ぶか設計する。一般論を無償の修正案にしてはいけない。
一時ファイルにも所有者が二種類ある。単体試験が作るDiskFileItemはfinallyで削除される。実要求のmultipart項目はWicketとCommonsのライフサイクルに従う。さらにExcelUtilsは受け取った配列から別の一時ファイルを作る。作成場所、削除時点、例外時の残留を区別して記録すれば、ディスク圧迫や権限問題の調査が早くなる。
透明性は未知を消さない
公開リポジトリによって外部から断言と実装を比較できるのは統治上の利点である。それでも、非公開の追加試験、本番ビルド、リバースプロキシの上限、運用手順までは分からない。分かるのは固定コミットに何が追加され、標本が何で、公開経路がどの統制を持つかである。記事は既知と未知を同時に残すべきだ。
その書き方は保守者を不当に評価しない。ディスク退避の互換境界を固定した点、画像経路に内容負例がある点、ワークブック経路がPOIと行検証へ進む点、結果画面に認可と終了状態がある点は肯定できる。改善対象は証拠同士の索引と名称であり、防御が存在しないと宣告することではない。
成熟したリリース記録なら、五枚の受領証を範囲付きで列挙できる。「転送合格」は対象ライブラリと保存分岐を示し、「形式合格」は本物の標本を示し、「手続合格」はアカウント種別と選挙状態を示す。「アップロードを修正した」という一文より少し長いが、後年の監査や更新でも意味が崩れにくい。
各受領証には失効条件も必要だ。Wicket、Commons FileUpload、一時ディレクトリ方針、アップロードの包み方が変われば転送を再確認する。POI、PDF受入方針、標本生成器が変われば形式を再確認する。列定義、選挙状態、権限、キューの意味が変われば業務と手続を再確認する。失効条件のない緑は、観測した環境が消えても残り続ける。「かつて合格」と「現在の版にも有効」を分ける記録が必要である。
この仕組みは試験量ではなく選択の正確さを改善する。表示文だけを変えた修正に全てのバイナリー解析を要求する必要はない。一方、multipartライブラリを替えた修正が、たまたま通った業務試験だけで承認されてもいけない。変更が触れた証拠の辺と直接依存する受領証を再実行する。共有リポジトリだから全てを一括扱いするのでも、速い単体試験を理由に影響層を省くのでもない。範囲を説明できることが、効率と保証を両立させる。
出典
- LACNIC選挙システムの説明
- 固定したLACNICコミット
- multipartアップロード互換性試験
- 組織Excelバリデーター
- 選挙結果ダッシュボード
- 結果通知書の補助コード
- ワークブック処理ユーティリティ
- 組織アップロードパネル
- 有権者名簿アップロードパネル
- Wicket 10.9.0のFileUploadソース
- Commons DiskFileItem文書
- Commons FileUpload利用ガイド
- Apache POIセキュリティ指針
- Apache POI ZipSecureFile文書
- OWASPファイルアップロードガイド
- LACNIC管理モジュールPOM
- LACNICのPOI OOXMLモジュール
会員向け解説
プロフィールの詳細
適切な会員レベルでログインすると、解説全文と出典メモをご覧いただけます。
Strategic Circle 限定
Strategic Circle
すべての読者に公開されています。参加してログインすると プロフィール解説 を閲覧できます。
Strategic Circle に参加Leadership Alliance 会員限定
Leadership Alliance
対象となる IP 資産の所有者・管理者向けです。ログインすると Leadership Alliance の解説を閲覧できます。
Leadership Alliance に参加
