POSA_LEAKSMS/tests/chaos_drill.php
cw2007 73e49fd528 feat: RPi4 누수+온습도 2-모듈 단일 서버 통합 + 보안 하드닝
2번 모듈 신규(raspberry_pi4_sht30/): SHT30 온습도 → cafe24, raw-body X-Signature HMAC, 폐쇄망 오프라인 설치(vendor/install), systemd, CRC/포맷 자가점검. firmware sht30_fw wire 포맷과 byte-parity 검증.

1번 모듈 통합(raspberry_pi4/): 누수+카메라를 동일 서버로. 레거시 sha256(key+json) body-sig → X-Signature HMAC 전환, 사진 canonical=device_id|sensor_id|log_id|timestamp.

서버 통합(php/): api/sensor_data.php 누수 이벤트 수신, api/photo_upload.php 신규(HMAC·finfo·서버생성 파일명·nonce 멱등·sensor 결속), photo.php 인증 사진서빙, dashboard.php 누수 패널+사진, sms_send.php 누수 SMS, config.php 태그/요약.

DB: sql/migration_add_leak.sql(가산·멱등), schema_sht30.sql 통합 스키마.

보안 하드닝(외부 펜테스트 대비, 확정 CRITICAL/HIGH 0): cron_heartbeat api_key fail-closed, setup_mfa 부트스트랩 토큰 post-enrollment 잠금, var/ PHP 실행차단, HSTS.

문서/테스트: SYSTEM_OVERVIEW.md, security_hardening_test.php 갱신. 참고: 사용자 요청으로 세션 외 기존 미커밋 변경도 함께 포함.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 16:21:11 +09:00

50 lines
2.3 KiB
PHP

<?php
// =============================================================================
// chaos_drill.php - 경보 실패 경로 드릴 (CLI 전용)
//
// SMS_FORCE_FAIL 을 주입해 실제 전송 없이 '발송 실패' 경로를 시험한다. 발송실패
// 가시화/재시도/잔액경보 등 *실패에 의존하는* 신뢰성 기능이 동작하는지 손시연 없이
// 검증한다(기존 회귀 테스트는 정상 경로만 본다).
//
// 라이브 종단 드릴(운영 점검): config.local.php 에 일시적으로 'SMS_FORCE_FAIL' => true
// 를 두고 임계 초과를 유발한 뒤, 대시보드의 '경보 SMS 발송 실패' 배너와 오프라인 재시도
// 예약(error_log)을 확인하고, 끝나면 반드시 다시 false 로 되돌린다.
//
// 주의: config.local.php 가 SMS_FORCE_FAIL 을 명시 설정하면 아래 env 주입은 무시된다.
// =============================================================================
declare(strict_types=1);
if (php_sapi_name() !== 'cli') {
http_response_code(403);
header('Content-Type: text/plain; charset=utf-8');
exit("CLI only\n");
}
putenv('SMS_FORCE_FAIL=1'); // config 로드 전에 주입(cfg 가 getenv 로 읽음)
$root = dirname(__DIR__);
require_once $root . '/php/sms_send.php'; // config.php 포함
$failures = [];
function chk(bool $cond, string $msg): void {
global $failures;
if (!$cond) { $failures[] = $msg; }
}
chk(SMS_FORCE_FAIL === true, 'SMS_FORCE_FAIL should be forced ON for the drill (env override). config.local.php 가 명시 설정하면 무시될 수 있음.');
$r = send_sms_cafe24('01000000000', '드릴 메시지');
chk(($r['success'] ?? null) === false, 'forced send must report failure (success=false).');
chk(($r['result_code'] ?? '') === 'FORCED_FAIL', 'forced send must use FORCED_FAIL result code.');
chk(array_key_exists('remaining', $r), 'result must include the remaining key.');
if ($failures) {
fwrite(STDERR, "Chaos drill FAILURES:\n");
foreach ($failures as $f) {
fwrite(STDERR, "- {$f}\n");
}
exit(1);
}
echo "Chaos drill passed: SMS 실패 주입 경로 동작 확인.\n";
echo "라이브 드릴: config.local.php 에 'SMS_FORCE_FAIL'=>true 후 임계초과 유발 → 대시보드 실패 배너/오프라인 재시도 확인 → 반드시 false 로 복구.\n";