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>
62 lines
3.1 KiB
PHP
62 lines
3.1 KiB
PHP
<?php
|
|
// =============================================================================
|
|
// config.local.example.php - v2606 (SHT30 온습도) 운영 설정 예시
|
|
//
|
|
// 1. 이 파일을 config.local.php로 복사합니다.
|
|
// 2. 실제 운영 값으로 교체합니다.
|
|
// 3. config.local.php는 서버에만 보관하고 공유하지 않습니다.
|
|
// =============================================================================
|
|
|
|
return [
|
|
'DB_HOST' => 'localhost',
|
|
'DB_PORT' => 3306,
|
|
'DB_NAME' => 'your_db_name',
|
|
'DB_USER' => 'your_db_user',
|
|
'DB_PASS' => 'your_db_password',
|
|
|
|
'API_KEY' => 'replace-with-long-random-secret',
|
|
|
|
// 요청 서명은 HMAC-SHA256(키=API_KEY, 메시지=요청본문 바이트)이며 X-Signature 헤더로
|
|
// 전송된다. 레거시 키-접두 sha256 폴백은 기본 비활성이고, 운영(STM32 HMAC 전용)에서는
|
|
// 반드시 false 로 둔다. 과거 RPi(레거시) 클라이언트가 아직 남아 있을 때만 true 로 켠다.
|
|
'ALLOW_LEGACY_BODY_SIGNATURE' => false,
|
|
|
|
'SMS_USER_ID' => 'your-cafe24-sms-user-id',
|
|
'SMS_SECURE' => 'your-cafe24-sms-secure-key',
|
|
'SMS_SENDER' => '01000000000',
|
|
'SMS_RECIPIENTS' => [
|
|
'01000000000',
|
|
],
|
|
|
|
'ADMIN_USER' => 'admin',
|
|
'ADMIN_PASSWORD_HASH' => '$2y$10$replace.with.password_hash.output',
|
|
// Base32 TOTP secret. MUST be left EMPTY here and set to a UNIQUE generated value in
|
|
// config.local.php. Empty '' => admin_mfa_configured() is false => login is DISABLED
|
|
// (fail-closed) until a real secret is set. NEVER put a literal Base32 string in this
|
|
// example file: any non-empty Base32-ish value (even "REPLACE_WITH_...") decodes to a
|
|
// usable, publicly-known TOTP secret and silently enables MFA on a known seed.
|
|
// Generate a unique secret on the server only:
|
|
// php -r "require 'php/admin_security.php'; echo admin_totp_secret().PHP_EOL;"
|
|
'ADMIN_TOTP_SECRET' => '',
|
|
// Temporary bootstrap token for setup_mfa.php. Remove or empty after MFA enrollment.
|
|
'MFA_SETUP_TOKEN' => 'replace-with-temporary-random-token',
|
|
|
|
// 온습도 임계 경보 (서버 판정 → SMS). 운영 환경에 맞게 조정.
|
|
'METRIC_TEMP_HIGH_C' => 30, // 고온 임계(℃)
|
|
'METRIC_TEMP_LOW_C' => 10, // 저온 임계(℃)
|
|
'METRIC_RH_HIGH' => 70, // 고습 임계(%)
|
|
'METRIC_RH_LOW' => 20, // 저습 임계(%)
|
|
'METRIC_ALERT_COOLDOWN_SEC' => 1800, // 동일 종류 경보 재발송 억제(초, 기본 30분)
|
|
|
|
// 미복귀 경보 2차(야간) 에스컬레이션 수신자. 비우면 비활성(opt-in).
|
|
'SMS_RECIPIENTS_TIER2' => [],
|
|
'ESCALATE_AFTER_SEC' => 1800, // 경보 미복귀 30분 후 2차 통지
|
|
// 아래는 기본값으로 동작(필요 시에만 override):
|
|
// METRIC_DEWPOINT_MARGIN_C(3℃ 결로), SMS_BALANCE_WARN_THRESHOLD(30건),
|
|
// HEALTH_SMS_HOUR(9시), STUCK_DETECT_SAMPLES(6), SMS_RETRY_OFFLINE(true)
|
|
|
|
'SMS_LOG_RETENTION_DAYS' => 365,
|
|
'SENSOR_LOG_RETENTION_DAYS' => 365,
|
|
'SENSOR_METRIC_RETENTION_DAYS' => 365,
|
|
'ADMIN_AUDIT_RETENTION_DAYS' => 365,
|
|
];
|