Class: Gitlab::UrlBlocker

Inherits:
Object
  • Object
show all
Defined in:
lib/gitlab/url_blocker.rb

Defined Under Namespace

Classes: Result

Constant Summary collapse

BlockedUrlError =
Class.new(StandardError)
DENY_ALL_REQUESTS_EXCEPT_ALLOWED_DEFAULT =
proc { deny_all_requests_except_allowed_app_setting }.freeze

Class Method Summary collapse

Class Method Details

.blocked_url?(url, **kwargs) ⇒ Boolean

Returns:

  • (Boolean)


111
112
113
114
115
116
117
# File 'lib/gitlab/url_blocker.rb', line 111

def blocked_url?(url, **kwargs)
  validate!(url, **kwargs)

  false
rescue BlockedUrlError
  true
end

.validate!Object

For backwards compatibility, Returns an array with [<uri>, <original-hostname>]. Issue for refactoring: gitlab.com/gitlab-org/gitlab/-/issues/410890



121
122
123
124
# File 'lib/gitlab/url_blocker.rb', line 121

def validate!(...)
  result = validate_url_with_proxy!(...)
  [result.uri, result.hostname]
end

.validate_url_with_proxy!(url, schemes:, ports: [], allow_localhost: false, allow_local_network: true, allow_object_storage: false, ascii_only: false, enforce_user: false, enforce_sanitization: false, deny_all_requests_except_allowed: DENY_ALL_REQUESTS_EXCEPT_ALLOWED_DEFAULT, dns_rebind_protection: true) ⇒ Object

Validates the given url according to the constraints specified by arguments.

ports - Raises error if the given URL port is not between given ports. allow_localhost - Raises error if URL resolves to a localhost IP address and argument is false. allow_local_network - Raises error if URL resolves to a link-local address and argument is false. allow_object_storage - Avoid raising an error if URL resolves to an object storage endpoint and argument is true. ascii_only - Raises error if URL has unicode characters and argument is true. enforce_user - Raises error if URL user doesn’t start with alphanumeric characters and argument is true. enforce_sanitization - Raises error if URL includes any HTML/CSS/JS tags and argument is true. deny_all_requests_except_allowed - Raises error if URL is not in the allow list and argument is true. Can be Boolean or Proc. Defaults to instance app setting.

Returns a Result object. rubocop:disable Metrics/ParameterLists

Raises:

  • (ArgumentError)


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/gitlab/url_blocker.rb', line 43

def validate_url_with_proxy!(
  url,
  schemes:,
  ports: [],
  allow_localhost: false,
  allow_local_network: true,
  allow_object_storage: false,
  ascii_only: false,
  enforce_user: false,
  enforce_sanitization: false,
  deny_all_requests_except_allowed: DENY_ALL_REQUESTS_EXCEPT_ALLOWED_DEFAULT,
  dns_rebind_protection: true)
  # rubocop:enable Metrics/ParameterLists

  return Result.new(nil, nil, true) if url.nil?

  raise ArgumentError, 'The schemes is a required argument' if schemes.blank?

  # Param url can be a string, URI or Addressable::URI
  uri = parse_url(url)

  validate_uri(
    uri: uri,
    schemes: schemes,
    ports: ports,
    enforce_sanitization: enforce_sanitization,
    enforce_user: enforce_user,
    ascii_only: ascii_only
  )

  begin
    address_info = get_address_info(uri)
  rescue SocketError
    proxy_in_use = uri_under_proxy_setting?(uri, nil)

    return Result.new(uri, nil, proxy_in_use) unless enforce_address_info_retrievable?(uri, dns_rebind_protection, deny_all_requests_except_allowed)

    raise BlockedUrlError, 'Host cannot be resolved or invalid'
  end

  ip_address = ip_address(address_info)
  proxy_in_use = uri_under_proxy_setting?(uri, ip_address)

  # Ignore DNS rebind protection when a proxy is being used, as DNS
  # rebinding is expected behavior.
  dns_rebind_protection &&= !proxy_in_use
  return Result.new(uri, nil, proxy_in_use) if domain_in_allow_list?(uri)

  protected_uri_with_hostname = enforce_uri_hostname(ip_address, uri, dns_rebind_protection, proxy_in_use)

  return protected_uri_with_hostname if ip_in_allow_list?(ip_address, port: get_port(uri))

  # Allow url from the GitLab instance itself but only for the configured hostname and ports
  return protected_uri_with_hostname if internal?(uri)

  return protected_uri_with_hostname if allow_object_storage && object_storage_endpoint?(uri)

  validate_deny_all_requests_except_allowed!(deny_all_requests_except_allowed)

  validate_local_request(
    address_info: address_info,
    allow_localhost: allow_localhost,
    allow_local_network: allow_local_network
  )

  protected_uri_with_hostname
end