fix(security): outbound URL 내부주소·host 검증 전수 강화
서버가 외부 입력으로 목적지가 제어되는 outbound HTTP 요청을 보내는 지점을 전수 조사해, 내부망(사설 IP·루프백·링크로컬·메타데이터)과 host 위조를 차단한다. KVE-2026-1546(이니시스 인증 URL 접두사 매칭 우회)과 동일 클래스의 지점(언어팩 URL 설치, 스케줄 URL 호출, 배송비 계산 API, GitHub URL 판정)을 코어 공용 유틸 App\Support\OutboundUrlValidator 로 수렴시켰다. - 접두사 매칭을 host 완전일치로 교체 — userinfo(@) 위장과 접미사 확장 도메인 우회 벡터 차단. - 사내 서버 호출이 정당한 관리자 지점(스케줄·외부 API)은 신규 설정 security.allow_internal_outbound_urls(기본 off)로 옵트인. - 언어팩 URL 설치는 원격 코드 다운로드라 옵트인과 무관하게 내부 주소 항상 차단. - 웹소켓 연결 테스트는 localhost·사설 IP 가 정상 구성이므로 구조적 위조만 차단. 각 지점에 red 재현 → 수정 → green 회귀 테스트 + 실브라우저 E2E 로 검증. 수기 API 문서가 자동 재생성으로 소실되는 사고를 막는 PreToolUse 훅을 함께 추가한다.
This commit is contained in:
1 parent
f848086fd6
commit
c4beb116ad
46 files changed
+1297
-55
No files matched your search
@@ -465,7 +465,7 @@ Content-Type: application/json
|
||||
|
||||
| 이름 | 위치 | 타입 | 필수 | 허용값 | 용도 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| url | body | string | 예 | max 500 | URL |
|
||||
| url | body | string | 예 | max 500 | 언어팩 ZIP 다운로드 URL. `https` 만 허용하며, 내부 네트워크 주소(사설 IP·루프백·`localhost`·`*.internal` 등)와 userinfo(`https://a@b/`) 위장 주소는 422 로 거부됩니다 — 서버가 대신 내려받는 요청이므로 내부망 접근을 막기 위함(SSRF). 원격 코드를 가져오는 경로라 `security.allow_internal_outbound_urls` 설정을 켜도 내부 주소는 계속 차단됩니다 |
|
||||
| checksum | body | string | 아니오 | — | 무결성 검증 체크섬 (SHA-256) |
|
||||
| auto_activate | body | boolean | 아니오 | — | 설치 후 자동 활성화 여부 |
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ HTTP/1.1 200
|
||||
| name | body | string | 예 | max 255 | 대상의 이름/명칭 |
|
||||
| description | body | string | 아니오 | max 1000 | 설명 |
|
||||
| type | body | string | 예 | `artisan`, `shell`, `url` | 작업 유형: artisan(Artisan 커맨드 실행), shell(쉘 명령 실행), url(URL 호출) |
|
||||
| command | body | string | 예 | max 2000 | 실행할 아티즌 커맨드 |
|
||||
| command | body | string | 예 | max 2000 | 실행할 명령 (`type` 에 따라 Artisan 커맨드 / 쉘 명령 / 호출할 URL). `type=url` 이면 내부 네트워크 주소(사설 IP·루프백·`localhost`·`*.internal` 등)는 거부되어 422 로 응답합니다 — 서버가 내부망으로 요청을 보내는 것을 막기 위함(SSRF). 사내 엔드포인트를 호출해야 하면 환경설정의 `security.allow_internal_outbound_urls` 를 켜세요. 이 설정을 켜도 userinfo(`https://a@b/`) 위장과 http/https 이외 scheme 은 계속 거부됩니다 |
|
||||
| expression | body | string | 예 | max 100 | 실행 시각을 정의하는 Cron 표현식 (예: `0 3 * * *`, 다음 실행 시각 next_run_at 계산의 기준) |
|
||||
| frequency | body | string | 예 | `everyMinute`, `hourly`, `daily`, `weekly`, `monthly`, `custom` | 실행 주기 |
|
||||
| without_overlapping | body | boolean | 아니오 | — | 중복 실행 방지 여부 |
|
||||
@@ -680,7 +680,7 @@ HTTP/1.1 200
|
||||
| name | body | string | 예 | max 255 | 대상의 이름/명칭 |
|
||||
| description | body | string | 아니오 | max 1000 | 설명 |
|
||||
| type | body | string | 예 | `artisan`, `shell`, `url` | 작업 유형: artisan(Artisan 커맨드 실행), shell(쉘 명령 실행), url(URL 호출) |
|
||||
| command | body | string | 예 | max 2000 | 실행할 아티즌 커맨드 |
|
||||
| command | body | string | 예 | max 2000 | 실행할 명령 (`type` 에 따라 Artisan 커맨드 / 쉘 명령 / 호출할 URL). `type=url` 이면 내부 네트워크 주소(사설 IP·루프백·`localhost`·`*.internal` 등)는 거부되어 422 로 응답합니다 — 서버가 내부망으로 요청을 보내는 것을 막기 위함(SSRF). 사내 엔드포인트를 호출해야 하면 환경설정의 `security.allow_internal_outbound_urls` 를 켜세요. 이 설정을 켜도 userinfo(`https://a@b/`) 위장과 http/https 이외 scheme 은 계속 거부됩니다 |
|
||||
| expression | body | string | 예 | max 100 | 실행 시각을 정의하는 Cron 표현식 (예: `0 3 * * *`, 다음 실행 시각 next_run_at 계산의 기준) |
|
||||
| frequency | body | string | 예 | `everyMinute`, `hourly`, `daily`, `weekly`, `monthly`, `custom` | 실행 주기 |
|
||||
| without_overlapping | body | boolean | 아니오 | — | 중복 실행 방지 여부 |
|
||||
|
||||
@@ -43,7 +43,7 @@ _단건 응답: `data` 객체의 필드._
|
||||
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
|
||||
| --- | --- | --- | --- |
|
||||
| general | object | `{"site_name":"Test Site","site_url":"https:\/\/test.examp…` | 일반 탭 설정 그룹 (사이트명·사이트 URL·설명·관리자 이메일·타임존·기본 언어·통화·점검 모드·사이트 로고 첨부). site_logo 는 SettingsService 가 별도 주입한 첨부 정보 |
|
||||
| security | object | `{"force_https":true,"login_attempt_enabled":true,"auth_to…` | 보안 탭 설정 그룹 (HTTPS 강제·로그인 시도 제한 사용·인증 토큰 유지시간(분, 0=무한)·최대 로그인 시도 횟수·잠금 시간) |
|
||||
| security | object | `{"force_https":true,"login_attempt_enabled":true,"auth_to…` | 보안 탭 설정 그룹 (HTTPS 강제·로그인 시도 제한 사용·인증 토큰 유지시간(분, 0=무한)·최대 로그인 시도 횟수·잠금 시간·내부 네트워크 주소 호출 허용). `allow_internal_outbound_urls`(boolean, 기본 false): 서버가 대신 호출하는 outbound 요청(예약 작업 URL 호출, 외부 API 연동)에서 사설 IP·`localhost` 등 내부 주소를 허용할지 여부 — 켜면 사내 서버 호출이 가능해지지만 서버가 내부망으로 요청을 보낼 수 있게 되므로 기본은 차단입니다. 언어팩 URL 설치는 원격 코드를 내려받으므로 이 설정과 무관하게 항상 내부 주소를 거부합니다 |
|
||||
| mail | object | `{"mailer":"smtp","host":"","port":587,"username":"","pass…` | 메일 탭 설정 그룹 (메일러 종류(smtp/mailgun/ses)·SMTP 호스트/포트/인증 정보·암호화 방식·발신자 주소/이름·Mailgun/SES 자격 정보) |
|
||||
| upload | object | `{"max_file_size":10,"allowed_extensions":["jpg","jpeg","p…` | 업로드 탭 설정 그룹 (최대 파일 크기(MB)·허용 확장자 목록·이미지 최대 가로/세로·이미지 품질) |
|
||||
| seo | object | `{"meta_title_suffix":"","meta_description":"","meta_keywo…` | SEO 탭 설정 그룹 (메타 타이틀 접미사·메타 설명/키워드·검색엔진 인증 코드·봇 감지·OG/Twitter 기본값·SEO 캐시·사이트맵·생성기 설정) |
|
||||
|
||||
Reference in new issue
Block a user