Reviewed-on: #402 Co-authored-by: miteruzo <miteruzo@naver.com> Co-committed-by: miteruzo <miteruzo@naver.com>
このコミットはPull リクエスト #402 でマージされました.
このコミットが含まれているのは:
@@ -0,0 +1,55 @@
|
||||
require 'resolv'
|
||||
require 'ipaddr'
|
||||
require 'uri'
|
||||
|
||||
module Preview
|
||||
class UrlSafety
|
||||
class UnsafeUrl < StandardError; end
|
||||
|
||||
FORBIDDEN_NETWORKS = [
|
||||
'0.0.0.0/8', '10.0.0.0/8', '100.64.0.0/10', '127.0.0.0/8',
|
||||
'169.254.0.0/16', '172.16.0.0/12', '192.0.0.0/24',
|
||||
'192.0.2.0/24', '192.168.0.0/16', '198.18.0.0/15',
|
||||
'198.51.100.0/24', '203.0.113.0/24', '224.0.0.0/4',
|
||||
'240.0.0.0/4', '::/128', '::1/128', 'fc00::/7', 'fe80::/10',
|
||||
'ff00::/8', '2001:db8::/32', '::ffff:0:0/96'
|
||||
].map { IPAddr.new(_1) }.freeze
|
||||
|
||||
def self.validate(raw_url)
|
||||
value = raw_url.to_s.strip
|
||||
if value.match?(/\A[a-z][a-z0-9+\-.]*:/i)
|
||||
unless value.match?(/\Ahttps?:\/\//i)
|
||||
raise UnsafeUrl, 'http または https の URL を指定してください.'
|
||||
end
|
||||
else
|
||||
value = "http://#{ value }"
|
||||
end
|
||||
uri = URI.parse(value)
|
||||
|
||||
unless ['http', 'https'].include?(uri.scheme&.downcase) && uri.host.present?
|
||||
raise UnsafeUrl, 'http または https の URL を指定してください.'
|
||||
end
|
||||
raise UnsafeUrl, 'userinfo つき URL は使用できません.' if uri.userinfo.present?
|
||||
|
||||
addresses = Resolv.getaddresses(uri.host)
|
||||
raise UnsafeUrl, 'URL のホストを解決できません.' if addresses.empty?
|
||||
|
||||
parsed_addresses = addresses.map { IPAddr.new(_1) }
|
||||
if parsed_addresses.any? { |address| forbidden?(address) }
|
||||
raise UnsafeUrl, '安全でない接続先は使用できません.'
|
||||
end
|
||||
|
||||
[uri, parsed_addresses.map(&:to_s)]
|
||||
rescue Resolv::ResolvError
|
||||
raise UnsafeUrl, 'URL のホストを解決できません.'
|
||||
rescue URI::InvalidURIError, IPAddr::InvalidAddressError
|
||||
raise UnsafeUrl, 'URL が不正です.'
|
||||
end
|
||||
|
||||
def self.forbidden?(address)
|
||||
FORBIDDEN_NETWORKS.any? { _1.include?(address) }
|
||||
end
|
||||
|
||||
private_class_method :forbidden?
|
||||
end
|
||||
end
|
||||
新しい課題から参照
ユーザをブロックする