Skip to content

Commit f36dc3e

Browse files
k-ibarakiclaude
andcommitted
fix(excel): Strengthen security validation and improve code consistency
Security improvements: - Reject reversed cell ranges (e.g., "A100:A1") as invalid input - More explicit validation instead of silently handling edge cases - Better protection against malicious range specifications Code improvements: - Use _parse_rows helper for sheet.iter_rows() to reduce duplication - Consistent code pattern across all data processing paths Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent f08022e commit f36dc3e

1 file changed

Lines changed: 38 additions & 17 deletions

File tree

src/sharepoint_excel.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,10 @@ def _parse_sheet(
225225

226226
# データサイズ検証(DoS対策)
227227
range_rows, range_cols = self._calculate_range_size(cell_range)
228-
if range_rows > config.excel_max_data_rows or range_cols > config.excel_max_data_cols:
228+
if (
229+
range_rows > config.excel_max_data_rows
230+
or range_cols > config.excel_max_data_cols
231+
):
229232
raise ValueError(
230233
f"データサイズ({range_rows}行 × {range_cols}列)が上限"
231234
f"({config.excel_max_data_rows}行 × {config.excel_max_data_cols}列)を超えています。"
@@ -243,24 +246,39 @@ def _parse_sheet(
243246
if header_range:
244247
header_data = sheet[header_range]
245248
header_rows_data = self._normalize_range_data(header_data)
246-
all_rows.extend(self._parse_rows(header_rows_data, include_formatting, merged_cell_map))
249+
all_rows.extend(
250+
self._parse_rows(
251+
header_rows_data, include_formatting, merged_cell_map
252+
)
253+
)
247254

248255
# データ範囲を取得(metadata_onlyの場合はスキップ)
249256
if not metadata_only:
250257
range_data = sheet[data_range]
251258
data_rows_data = self._normalize_range_data(range_data)
252-
all_rows.extend(self._parse_rows(data_rows_data, include_formatting, merged_cell_map))
259+
all_rows.extend(
260+
self._parse_rows(
261+
data_rows_data, include_formatting, merged_cell_map
262+
)
263+
)
253264
else:
254265
# 通常のセル範囲取得(metadata_onlyの場合もヘッダーなしなので取得)
255266
if not metadata_only:
256267
range_data = sheet[cell_range]
257268
rows_to_process = self._normalize_range_data(range_data)
258-
all_rows.extend(self._parse_rows(rows_to_process, include_formatting, merged_cell_map))
269+
all_rows.extend(
270+
self._parse_rows(
271+
rows_to_process, include_formatting, merged_cell_map
272+
)
273+
)
259274
elif sheet.dimensions:
260275
# シート全体を取得
261276
# データサイズ検証(DoS対策)
262277
sheet_rows, sheet_cols = self._calculate_range_size(sheet.dimensions)
263-
if sheet_rows > config.excel_max_data_rows or sheet_cols > config.excel_max_data_cols:
278+
if (
279+
sheet_rows > config.excel_max_data_rows
280+
or sheet_cols > config.excel_max_data_cols
281+
):
264282
raise ValueError(
265283
f"シート全体のサイズ({sheet_rows}行 × {sheet_cols}列)が上限"
266284
f"({config.excel_max_data_rows}行 × {config.excel_max_data_cols}列)を超えています。"
@@ -269,22 +287,18 @@ def _parse_sheet(
269287
)
270288

271289
# metadata_onlyの場合はヘッダーのみ取得
290+
rows_to_process = None
272291
if metadata_only and include_header and frozen_rows > 0:
273292
# ヘッダー行のみ取得
274-
for row in sheet.iter_rows(max_row=frozen_rows):
275-
row_data = [
276-
self._parse_cell(cell, include_formatting, merged_cell_map)
277-
for cell in row
278-
]
279-
all_rows.append(row_data)
293+
rows_to_process = tuple(sheet.iter_rows(max_row=frozen_rows))
280294
elif not metadata_only:
281295
# 全データを取得
282-
for row in sheet.iter_rows():
283-
row_data = [
284-
self._parse_cell(cell, include_formatting, merged_cell_map)
285-
for cell in row
286-
]
287-
all_rows.append(row_data)
296+
rows_to_process = tuple(sheet.iter_rows())
297+
298+
if rows_to_process:
299+
all_rows.extend(
300+
self._parse_rows(rows_to_process, include_formatting, merged_cell_map)
301+
)
288302

289303
# レスポンス形式の分岐
290304
if include_header:
@@ -452,6 +466,13 @@ def _calculate_range_size(self, range_str: str) -> tuple[int, int]:
452466
start_col_idx = column_index_from_string(start_col)
453467
end_col_idx = column_index_from_string(end_col)
454468

469+
# 逆順序の範囲を検出(セキュリティ対策)
470+
if end_row < start_row or end_col_idx < start_col_idx:
471+
raise ValueError(
472+
f"無効なセル範囲: '{range_str}'。"
473+
f"範囲は正しい順序で指定してください(例: 'A1:Z100')"
474+
)
475+
455476
rows = end_row - start_row + 1
456477
cols = end_col_idx - start_col_idx + 1
457478

0 commit comments

Comments
 (0)