------------------------------------------------------------------- safeHTTPClient initializes a custom http.Client with extra host checks to prevent internal network probing requests (aka. disallow loopback, private, multicast, etc. requests). NB! The host checks are not perfect and there are prob
()
| 435 | // |
| 436 | // @todo Evaluate with the refactoring if worth exporting(+tests) and moving under the security package. |
| 437 | func safeHTTPClient() *http.Client { |
| 438 | dialer := &net.Dialer{ |
| 439 | // the same options as in http.DefaultTransport.DialContext |
| 440 | Timeout: 30 * time.Second, |
| 441 | KeepAlive: 30 * time.Second, |
| 442 | |
| 443 | // check the address right after estrablishing the connection to prevent dns rebinding |
| 444 | Control: func(network, address string, c syscall.RawConn) error { |
| 445 | host, _, err := net.SplitHostPort(address) |
| 446 | if err != nil { |
| 447 | return err |
| 448 | } |
| 449 | |
| 450 | ip := net.ParseIP(host) |
| 451 | |
| 452 | if ip == nil || |
| 453 | ip.IsLoopback() || |
| 454 | ip.IsUnspecified() || |
| 455 | ip.IsPrivate() || |
| 456 | ip.IsLinkLocalUnicast() || |
| 457 | ip.IsLinkLocalMulticast() || |
| 458 | ip.IsMulticast() { |
| 459 | return fmt.Errorf("address %q is invalid or resolve to disallowed IP", address) |
| 460 | } |
| 461 | |
| 462 | return nil |
| 463 | }, |
| 464 | } |
| 465 | |
| 466 | return &http.Client{ |
| 467 | Timeout: 180 * time.Second, // can be still cancelled with the request context |
| 468 | Transport: &http.Transport{ |
| 469 | DialContext: dialer.DialContext, |
| 470 | // the same options as in http.DefaultTransport |
| 471 | ForceAttemptHTTP2: true, |
| 472 | MaxIdleConns: 100, |
| 473 | IdleConnTimeout: 90 * time.Second, |
| 474 | TLSHandshakeTimeout: 10 * time.Second, |
| 475 | ExpectContinueTimeout: 1 * time.Second, |
| 476 | }, |
| 477 | } |
| 478 | } |
| 479 | |
| 480 | // safeFileFromURL downloads the file from the specified url (using safeHTTPClient) |
| 481 | // and creates a new filesystem.File value from its content (limited to DefaultMaxBodySize). |
no outgoing calls
no test coverage detected
searching dependent graphs…