fix(installer): 설치 상태 파일에 관리자 비밀번호가 평문으로 잔존하는 문제
비밀을 state.json(0664, 실패 시 무기한 잔존)에 기록하지 않고 runtime.php(0600, finalize 시 삭제)로 채널을 일원화한다. 정상 완료 경로에서는 finalize 가 state.json 을 삭제하지만, finalize 미호출 / unlink 실패 / 설치 중단 시에는 평문이 영구히 남았고, finalize 가드가 재호출을 410 차단해 자가 회복도 불가능했다. 삭제라는 단일 경로에 의존해 평문을 보호하던 구조 자체를 제거한다. SSE 워커는 세션에 접근할 수 없어 파일 경유가 불가피한데, 그 파일이 0664 의 state.json 이었던 것이 구조적 원인이다. 세션을 보유한 유일한 공통 시작점인 install-process.php 를 비밀 이송 지점으로 삼고, db_seed 가 소비한 즉시 제거한다. 레거시 / 실패 경로는 완료·중단·초기화·finalize 시점 redact 로 방어. 동반 수정: - 세션 config 재병합으로 무력화되던 기존 DB 비밀번호 마스킹 복구 - db_seed 후 putenv 미해제로 모든 exec 자식에 평문이 ENV 상속되던 누출 차단 - runtime read 비밀번호 폴백이 write 값으로 잘못 대체되던 문제 ( 인접) 이미 설치된 사이트는 7.0.4 업그레이드 스텝이 잔존 파일을 정리한다. 완료 증거가 있으면 삭제하고, 설치 진행 중일 수 있으면 비밀만 제거한다.
This commit is contained in:
@@ -408,6 +408,35 @@ ENV;
|
||||
$this->assertStringContainsString('DB_WRITE_HOST=user-input.com', $merged);
|
||||
}
|
||||
|
||||
/**
|
||||
* 이슈 #465 불변식 — runtime.php 의 admin 섹션은 절대 `.env` 로 새어나가지 않는다.
|
||||
*
|
||||
* mergeRuntimeIntoEnv 는 db/app.key 만 명시 치환하는 화이트리스트 방식이다.
|
||||
* 이후 누군가 "runtime 배열을 통째로 .env 로 덤프" 하는 방식으로 리팩터링하면
|
||||
* 관리자 평문 비밀번호가 .env 에 영구 기록되므로, 그 회귀를 여기서 차단한다.
|
||||
*/
|
||||
public function test_merge_runtime_into_env_never_writes_admin_section(): void
|
||||
{
|
||||
$envContent = "APP_KEY=\nDB_WRITE_PASSWORD=\n";
|
||||
|
||||
$runtime = [
|
||||
'db' => [
|
||||
'write' => ['host' => 'h', 'port' => '3306', 'database' => 'd', 'username' => 'u', 'password' => 'dbpw'],
|
||||
],
|
||||
'app' => ['key' => 'base64:'.base64_encode(str_repeat('k', 32))],
|
||||
'admin' => ['password' => 'super-secret-admin-pw'],
|
||||
];
|
||||
|
||||
$merged = mergeRuntimeIntoEnv($envContent, $runtime);
|
||||
|
||||
$this->assertStringNotContainsString('super-secret-admin-pw', $merged, '관리자 평문이 .env 로 유출되면 안 됨');
|
||||
$this->assertStringNotContainsString('ADMIN', $merged, 'ADMIN 계열 키가 .env 에 기록되면 안 됨');
|
||||
|
||||
// db/app.key 는 정상 기록 (화이트리스트가 좁아지지 않았음을 함께 고정)
|
||||
$this->assertStringContainsString('DB_WRITE_PASSWORD="dbpw"', $merged);
|
||||
$this->assertStringContainsString('APP_KEY=base64:', $merged);
|
||||
}
|
||||
|
||||
public function test_merge_escapes_password_with_special_characters(): void
|
||||
{
|
||||
$envContent = "DB_WRITE_PASSWORD=\n";
|
||||
|
||||
Reference in New Issue
Block a user