$schemes 허용 scheme (기본 http/https — 사내 API 는 http 인 경우가 있다) * @param bool $allowInternalOptIn 관리자 설정으로 내부 주소를 허용할 수 있는 지점인지 (기본 true) */ public function __construct( private readonly array $schemes = ['http', 'https'], private readonly bool $allowInternalOptIn = true, ) {} /** * 값이 공개 인터넷 URL 인지 검증합니다. * * @param string $attribute 검증 대상 필드명 * @param mixed $value 검증 대상 값 * @param Closure $fail 실패 콜백 */ public function validate(string $attribute, mixed $value, Closure $fail): void { if ($value === null || $value === '') { return; } if (! is_string($value)) { $fail(__('validation.outbound_url.invalid')); return; } $options = ['schemes' => $this->schemes]; // 내부 주소 허용이 켜져 있으면 구조 검증(scheme/userinfo)만 하고 내부망 차단은 건너뛴다 if ($this->allowInternalOptIn && (bool) g7_core_settings('security.allow_internal_outbound_urls', false)) { if (! OutboundUrlValidator::isStructurallySafeUrl($value, $options)) { $fail(__('validation.outbound_url.invalid')); } return; } if (! OutboundUrlValidator::isPublicHttpUrl($value, $options)) { $fail(__('validation.outbound_url.internal_not_allowed')); } } }