설정
Config
type Config struct {
Timeouts *TimeoutConfig
Connection *ConnectionConfig
Security *SecurityConfig
Retry *RetryConfig
Middleware *MiddlewareConfig
}메인 설정 구조체로, DefaultConfig()를 통해 보안 기본값을 얻을 수 있습니다.
하위 설정은 포인터
v1.5.1 부터 다섯 가지 하위 설정은 모두 포인터 타입입니다. DefaultConfig()와 모든 프리셋 함수 (SecureConfig, PerformanceConfig 등) 는 이 포인터들을 비어 있지 않은 구조체로 자동 초기화하므로, cfg.Timeouts.Request, cfg.Security.AllowPrivateIPs 등의 필드 접근을 직접 사용할 수 있습니다. Config{} 리터럴을 수동으로 구성할 때는 &httpc.TimeoutConfig{...} 형태로 할당해야 하며, 사용 전에 포인터가 nil 이 아닌지 확인해야 합니다.
cfg := httpc.DefaultConfig()
cfg.Timeouts.Request = 60 * time.Second
cfg.Retry.MaxRetries = 5
client, err := httpc.New(cfg)TimeoutConfig
type TimeoutConfig struct {
Request time.Duration // 총 요청 타임아웃 (재시도 포함), 기본 180s
Dial time.Duration // TCP 연결 타임아웃, 기본 10s
TLSHandshake time.Duration // TLS 핸드셰이크 타임아웃, 기본 10s
ResponseHeader time.Duration // 응답 헤더 대기 타임아웃, 기본 0 (비활성화, 컨텍스트 타임아웃에 의존)
IdleConn time.Duration // 유휴 연결 유지 시간, 기본 90s
}| 필드 | 기본값 | 최대값 |
|---|---|---|
| Request | 180s | 30min |
| Dial | 10s | 30min |
| TLSHandshake | 10s | 30min |
| ResponseHeader | 0 | 30min |
| IdleConn | 90s | 30min |
0 으로 설정하면 타임아웃 없음 (프로덕션 환경에서는 권장하지 않음).
ResponseHeader 설계
ResponseHeader는 기본값이 0(비활성화) 이며, 이때 TimeoutConfig.Request 또는 WithTimeout()이 유일한 타임아웃 메커니즘으로 작동하여 WithTimeout()이 요청 지속 시간을 완전히 제어합니다. 이 설계는 AI API 와 롱 폴링 등 응답 시간 연장이 필요한 시나리오에 적합합니다. 전송 계층의 엄격한 상한 (Slowloris 공격 방어 등) 이 필요한 경우에만 양수로 설정하되, 이는 WithTimeout을 덮어쓴다는 점에 유의하세요.
ConnectionConfig
type ConnectionConfig struct {
MaxIdleConns int // 전역 최대 유휴 연결, 기본 50
MaxConnsPerHost int // 호스트당 최대 연결 수, 기본 10
ProxyURL string // 프록시 주소, 예: "http://proxy:8080"
EnableSystemProxy bool // 시스템 프록시 자동 감지, 기본 false
EnableHTTP2 bool // HTTP/2 활성화, 기본 true
EnableCookies bool // Cookie 관리 활성화, 기본 false
EnableDoH bool // DNS-over-HTTPS 활성화, 기본 false
DoHCacheTTL time.Duration // DoH 캐시 TTL, 기본 5min
MaxResponseHeaderBytes int64 // 응답 헤더 최대 바이트 수, 기본 0 (Go 표준 라이브러리 기본값 10MB 사용)
}DNS-over-HTTPS
DoH 를 활성화하여 DNS 해석 지연을 줄이고 DNS 하이재킹을 방지합니다:
cfg := httpc.DefaultConfig()
cfg.Connection.EnableDoH = true
cfg.Connection.DoHCacheTTL = 5 * time.Minute기본 DoH 제공자 (우선순위 순): Cloudflare → Google → AliDNS. 자세한 내용은 연결 풀과 프록시를 참조하세요.
SecurityConfig
type SecurityConfig struct {
TLSConfig *tls.Config // 커스텀 TLS 설정
MinTLSVersion uint16 // 최소 TLS 버전, 기본 TLS 1.2
MaxTLSVersion uint16 // 최대 TLS 버전, 기본 TLS 1.3
InsecureSkipVerify bool // 인증서 검증 건너뛰기 (테스트만)
MaxResponseBodySize int64 // 응답 본문 크기 제한, 기본 10MB
MaxRequestBodySize int64 // 요청 본문 크기 제한, 기본 0 (요청 본문 크기를 제한하지 않음; MaxResponseBodySize 와 달리 자동 폴백 없음)
MaxDecompressedBodySize int64 // 압축 해제 후 크기 제한, 기본 100MB
AllowPrivateIPs bool // 사설 IP 허용, 기본 false
SSRFExemptCIDRs []string // SSRF 면제 CIDR
ValidateURL bool // URL 검증, 기본 true
ValidateHeaders bool // 요청 헤더 검증, 기본 true
StrictContentLength bool // 엄격한 Content-Length, 기본 true
CookieSecurity *CookieSecurityConfig // Cookie 보안 검증
CertificatePinner CertificatePinner // 인증서 고정 (SPKI 해시/공개키), 기본 nil (비활성화)
RedirectWhitelist []string // 리다이렉트 허용 도메인
}인증서 고정 (CertificatePinner)
CertificatePinner는 인증서 고정을 활성화합니다: 서버가 고정된 키/인증서를 제공하지 않으면 TLS 핸드셰이크가 거부되므로, 신뢰할 수 있는 CA 가 침해되더라도 중간자 공격을 방어할 수 있습니다. 기본값은 nil(비활성화) 입니다. 다음 생성자로 만듭니다:
| 생성자 | 설명 |
|---|---|
NewSPKIHashPinner(hashes ...string) (CertificatePinner, error) | 하나 이상의 base64 인코딩된 SPKI SHA-256 해시로 생성 (가장 일반적으로 사용, 키 로테이션 지원) |
NewPublicKeyPinner(publicKeys ...[]byte) (CertificatePinner, error) | DER 인코딩된 PKIX 공개키로 생성 (내부적으로 SHA-256 계산) |
NewCertificatePinnerChain(pinners ...CertificatePinner) CertificatePinner | 여러 pinner 를 조합, 어느 하나라도 통과하면 수락 |
pinner, err := httpc.NewSPKIHashPinner(
"YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2fuihg=", // 현재 키
"C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=", // 백업 키 (로테이션)
)
if err != nil {
log.Fatal(err)
}
cfg := httpc.DefaultConfig()
cfg.Security.CertificatePinner = pinner
client, err := httpc.New(cfg)유지보수 비용
인증서 고정은 서버가 인증서를 교체할 때 (예: Let's Encrypt 갱신) 고정 값도 함께 업데이트해야 합니다. 여러 해시 (현재 + 백업) 를 고정하고 업데이트 메커니즘을 구축하여 키 로테이션으로 인한 연결 중단을 방지하는 것을 권장합니다.
SSRF 방어
AllowPrivateIPs는 기본값이 false이며, 사설/예약 IP(127.0.0.1, 10.x, 192.168.x 등) 연결을 차단합니다. 내부 서비스에 연결할 때만 true로 설정하세요.
SSRF 면제 예제
cfg := httpc.DefaultConfig()
cfg.Security.SSRFExemptCIDRs = []string{
"10.0.0.0/8", // VPC 내부
"100.64.0.0/10", // Tailscale
}RetryConfig
type RetryConfig struct {
MaxRetries int // 최대 재시도 횟수, 기본 3
Delay time.Duration // 초기 재시도 지연, 기본 1s
BackoffFactor float64 // 백오프 배수, 기본 2.0
EnableJitter bool // 지터 활성화, 기본 true
MaxRetryDelay time.Duration // 최대 재시도 지연 상한, 기본 30s
CustomPolicy RetryPolicy // 커스텀 재시도 전략
}| 필드 | 기본값 | 범위 |
|---|---|---|
| MaxRetries | 3 | 0-10 |
| Delay | 1s | 0-30min |
| BackoffFactor | 2.0 | 1.0-10.0 |
| MaxRetryDelay | 30s | 0-30min |
재시도 지연 공식: min(Delay * BackoffFactor^attempt + jitter, MaxRetryDelay)
MiddlewareConfig
type MiddlewareConfig struct {
Middlewares []MiddlewareFunc // 미들웨어 목록
UserAgent string // User-Agent, 기본 "httpc/1.0"
Headers map[string]string // 기본 요청 헤더
FollowRedirects bool // 리다이렉트 따라가기, 기본 true
MaxRedirects int // 최대 리다이렉트 횟수, 기본 10
}설정 프리셋
DefaultConfig
func DefaultConfig() *Config보안 기본 설정. SSRF 방어가 기본적으로 활성화되어 있습니다.
SecureConfig
func SecureConfig() *Config보안 우선 설정. 더 짧은 타임아웃, 자동 리다이렉트 비활성화, 엄격한 SSRF 방어.
| 설정 항목 | 값 |
|---|---|
| Request 타임아웃 | 15s |
| Dial 타임아웃 | 5s |
| TLSHandshake 타임아웃 | 5s |
| ResponseHeader 타임아웃 | 10s (Slowloris 방어) |
| IdleConn 타임아웃 | 30s |
| MaxIdleConns | 20 |
| MaxConnsPerHost | 5 |
| MaxResponseBodySize | 5MB |
| MaxRetries | 1 |
| Delay | 2s |
| EnableJitter | true |
| FollowRedirects | false |
PerformanceConfig
func PerformanceConfig() *Config고처리량 설정. 더 큰 연결 풀, 더 긴 타임아웃, 보안 검증은 유지.
TIP
PerformanceConfig 은 보안을 위해 ValidateURL과 ValidateHeaders를 활성화 상태로 유지합니다. 신뢰할 수 있는 환경에서 최대 성능이 필요한 경우 cfg.Security.ValidateURL = false로 수동 비활성화할 수 있으나, 보안 위험 (주입 공격, SSRF) 에 주의하세요.
| 설정 항목 | 값 |
|---|---|
| Request 타임아웃 | 60s |
| Dial 타임아웃 | 15s |
| TLSHandshake 타임아웃 | 15s |
| ResponseHeader 타임아웃 | 0 (비활성화, Request 타임아웃 사용) |
| IdleConn 타임아웃 | 120s |
| MaxIdleConns | 100 |
| MaxConnsPerHost | 20 |
| EnableCookies | true |
| MaxResponseBodySize | 50MB |
| StrictContentLength | false |
| ValidateURL | true |
| ValidateHeaders | true |
| Delay | 500ms |
| BackoffFactor | 1.5 |
| EnableJitter | true |
TestingConfig
func TestingConfig() *Config테스트 환경 설정. 보안 검사 비활성화, 짧은 타임아웃.
| 설정 항목 | 값 |
|---|---|
| Dial 타임아웃 | 5s |
| TLSHandshake 타임아웃 | 5s |
| ResponseHeader 타임아웃 | 0 (비활성화, Request 타임아웃 사용) |
| IdleConn 타임아웃 | 30s |
| MaxIdleConns | 10 |
| MaxConnsPerHost | 5 |
| EnableHTTP2 | false |
| EnableCookies | true |
| InsecureSkipVerify | true |
| AllowPrivateIPs | true |
| ValidateURL | false |
| ValidateHeaders | false |
| MaxRetries | 1 |
| Delay | 100ms |
| EnableJitter | false |
| UserAgent | httpc-test/1.0 |
DANGER
이 설정은 TLS 검증과 SSRF 방어를 비활성화하므로 테스트에만 사용하세요. 테스트 환경 외부에서 사용하면 보안 경고가 출력됩니다 (자세한 내용은 보안 경고 출력 참조).
MinimalConfig
func MinimalConfig() *Config경량 설정. 재시도와 리다이렉트 비활성화, 최소 연결 풀.
| 설정 항목 | 값 |
|---|---|
| Dial 타임아웃 | 5s |
| TLSHandshake 타임아웃 | 5s |
| ResponseHeader 타임아웃 | 0 (비활성화, Request 타임아웃 사용) |
| IdleConn 타임아웃 | 30s |
| MaxIdleConns | 10 |
| MaxConnsPerHost | 2 |
| MaxResponseBodySize | 1MB |
| MaxRetries | 0 |
| Delay | 0 |
| BackoffFactor | 1.0 |
| EnableJitter | false |
| FollowRedirects | false |
보안 경고 출력
SetSecurityWarnOutput
func SetSecurityWarnOutput(w io.Writer)보안 경고의 출력 대상을 설정합니다. TestingConfig()를 사용하거나 SecurityConfig.InsecureSkipVerify(Config.Security) 를 true로 설정하면, httpc 는 이 writer 에 [SECURITY WARNING] 수준의 경고를 출력합니다 (각 경고 유형별로 프로세스당 최대 한 번). 기본 출력은 os.Stderr이며, io.Discard를 전달하면 경고를 완전히 억제하여 테스트나 이미 알려진 안전한 내부 시나리오에서 조용히 실행할 수 있습니다.
// 테스트에서 보안 경고 억제
httpc.SetSecurityWarnOutput(io.Discard)
cfg := httpc.TestingConfig()영향 범위
이 설정은 프로세스 수준의 전역 상태이며, 이후에 생성되는 모든 클라이언트에 영향을 줍니다. TestingConfig와 InsecureSkipVerify 두 가지 경고는 각각 독립적으로 카운트됩니다 (서로의 트리거에 영향을 주지 않음), 하지만 동일한 출력 writer 를 공유합니다.
검증
ValidateConfig
func ValidateConfig(cfg *Config) error설정의 유효성을 검증합니다. New() 내부에서 자동 호출되지만, 명시적으로 호출할 수도 있습니다.
cfg := httpc.DefaultConfig()
cfg.Retry.MaxRetries = 100 // 범위 초과
if err := httpc.ValidateConfig(cfg); err != nil {
log.Fatal(err) // invalid retry configuration: Retry.MaxRetries must be 0-10, got 100
}Config.String
func (c *Config) String() string안전한 문자열 표현을 반환합니다. ProxyURL 자격 증명은 마스킹되고, TLSConfig 는 <configured> 또는 <default>로 표시되며, Headers 는 출력되지 않습니다.
cfg := httpc.DefaultConfig()
fmt.Println(cfg.String())
// Config{Timeouts:{Request: 3m0s, ...}, Security:{TLSConfig: <default>, ...}}Cookie 보안
CookieSecurityConfig
type CookieSecurityConfig struct {
RequireSecure bool
RequireHttpOnly bool
RequireSameSite string
AllowSameSiteNone bool
RequireSecureForSameSiteNone bool
}Cookie 보안 속성 검증 설정.
| 필드 | 타입 | 설명 |
|---|---|---|
| RequireSecure | bool | Cookie 에 Secure 속성 설정 요구 |
| RequireHttpOnly | bool | Cookie 에 HttpOnly 속성 설정 요구 |
| RequireSameSite | string | 요구되는 SameSite 값, 예: "Strict", "Lax", 빈 문자열은 검사하지 않음 |
| AllowSameSiteNone | bool | SameSite=None 허용 여부 |
| RequireSecureForSameSiteNone | bool | SameSite=None 일 때 Secure 속성 요구 (기본 true) |
DefaultCookieSecurityConfig
func DefaultCookieSecurityConfig() *CookieSecurityConfig기본 Cookie 보안 설정. Secure/HttpOnly/SameSite 속성을 요구하지 않지만, SameSite=None 인 Cookie 는 반드시 Secure 를 설정해야 합니다.
StrictCookieSecurityConfig
func StrictCookieSecurityConfig() *CookieSecurityConfig엄격한 Cookie 보안 설정. Secure, HttpOnly 및 SameSite=Strict 을 요구합니다.
cfg := httpc.DefaultConfig()
cfg.Security.CookieSecurity = httpc.StrictCookieSecurityConfig()