When web scraping with Ruby, you may encounter SSL certificate verification issues, especially when dealing with self-signed certificates, expired certificates, or internal development servers. This guide shows how to bypass SSL verification safely across different Ruby HTTP libraries.
⚠️ Security Warning
Disabling SSL verification poses significant security risks: - Makes requests vulnerable to man-in-the-middle attacks - Allows attackers to intercept and modify data - Should only be used in controlled environments
Only disable SSL verification when: - Testing against development servers - Working with trusted internal networks - Dealing with known self-signed certificates - Performance testing scenarios
Method 1: Net::HTTP (Built-in Library)
Ruby's built-in Net::HTTP
library provides direct control over SSL settings:
require 'net/http'
require 'openssl'
def scrape_with_disabled_ssl(url_string)
url = URI.parse(url_string)
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # Disable SSL verification
# Optional: Set additional SSL options
http.ssl_timeout = 30
http.open_timeout = 10
http.read_timeout = 30
request = Net::HTTP::Get.new(url.request_uri)
request['User-Agent'] = 'Ruby Web Scraper 1.0'
response = http.request(request)
case response
when Net::HTTPSuccess
response.body
when Net::HTTPRedirection
puts "Redirected to: #{response['location']}"
nil
else
puts "HTTP Error: #{response.code} #{response.message}"
nil
end
rescue => e
puts "Error: #{e.message}"
nil
end
# Usage
content = scrape_with_disabled_ssl('https://self-signed-cert-site.com')
puts content if content
Method 2: Faraday (Popular HTTP Client)
Faraday offers a more flexible approach with middleware support:
require 'faraday'
# Basic SSL bypass
conn = Faraday.new(
url: 'https://example.com',
ssl: { verify: false }
) do |faraday|
faraday.adapter Faraday.default_adapter
faraday.headers['User-Agent'] = 'Faraday Scraper'
end
response = conn.get('/some_page')
puts response.body
# Advanced configuration with connection pooling
class WebScraper
def initialize
@connection = Faraday.new do |conn|
conn.ssl.verify = false
conn.ssl.timeout = 30
# Add middleware for better error handling
conn.response :raise_error
conn.response :follow_redirects, limit: 3
conn.headers = {
'User-Agent' => 'Advanced Ruby Scraper',
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
}
conn.adapter Faraday.default_adapter
end
end
def fetch(url)
response = @connection.get(url)
response.body
rescue Faraday::Error => e
puts "Faraday error: #{e.message}"
nil
end
end
# Usage
scraper = WebScraper.new
content = scraper.fetch('https://problematic-ssl-site.com/data')
Method 3: HTTParty (Simple HTTP Client)
HTTParty provides the simplest syntax for quick scraping tasks:
require 'httparty'
# Simple one-liner
response = HTTParty.get('https://example.com', verify: false)
puts response.body
# Class-based approach with configuration
class ApiScraper
include HTTParty
# Global configuration
default_options.update(verify: false) # Disable SSL verification
headers 'User-Agent' => 'HTTParty Scraper'
timeout 30
def self.fetch_data(endpoint)
get(endpoint,
verify: false,
headers: { 'Accept' => 'application/json' }
)
rescue => e
puts "Error fetching data: #{e.message}"
nil
end
end
# Usage
data = ApiScraper.fetch_data('https://api.example.com/data')
puts data.parsed_response if data
Method 4: RestClient (Alternative Library)
require 'rest-client'
# Disable SSL verification globally
RestClient::Request.execute(
method: :get,
url: 'https://example.com/api/data',
verify_ssl: false,
headers: { 'User-Agent' => 'RestClient Scraper' }
)
# Or create a reusable resource
resource = RestClient::Resource.new(
'https://api.example.com',
verify_ssl: false,
headers: { 'User-Agent' => 'RestClient Scraper' }
)
response = resource['/endpoint'].get
puts response.body
Better Alternatives to Disabling SSL
Instead of completely disabling SSL verification, consider these safer alternatives:
1. Custom Certificate Bundle
require 'net/http'
require 'openssl'
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.ca_file = '/path/to/custom/certificate/bundle.pem'
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
2. Environment-Specific Configuration
class ConfigurableHttpClient
def self.create_client(url)
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
if Rails.env.development? || Rails.env.test?
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
else
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
end
http
end
end
3. Conditional SSL Bypass
def safe_http_request(url_string, skip_ssl_verify: false)
url = URI.parse(url_string)
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
if skip_ssl_verify
puts "WARNING: SSL verification disabled for #{url.host}"
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
else
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
end
# Continue with request...
end
Error Handling Best Practices
Always implement proper error handling when bypassing SSL:
def robust_scraper(url)
begin
# Your scraping code here
rescue OpenSSL::SSL::SSLError => e
puts "SSL Error: #{e.message}"
puts "Consider using verify: false for development only"
nil
rescue Net::TimeoutError => e
puts "Request timed out: #{e.message}"
nil
rescue => e
puts "Unexpected error: #{e.class} - #{e.message}"
nil
end
end
Summary
While disabling SSL verification can solve certificate-related scraping issues, it should be used judiciously and only in appropriate contexts. Always prefer proper certificate management in production environments, and consider the security implications of your scraping activities.