Ruby Sinatra create post request without PEM and OpenSSL::SSL::VERIFY_NONE - ruby

I try create POST request with SSL but without OpenSSL::SSL::VERIFY_NONE because it is opend up security attacks and without PEM certificate.
But I catch problems, my ruby code for send POST request:
post '/test/test1' do
cross_origin
post_data = request.body.read
res_Data = JSON.parse(post_data)
userName = res_Data['username']
#responseFromServer=''
uri = URI('https://test.com/test1')
Net::HTTP.start(uri.host, uri.port,
:use_ssl => uri.scheme == 'https',
:verify_mode => OpenSSL::SSL::VERIFY_NONE) do |http|
request = Net::HTTP::Post.new uri.request_uri
request.basic_auth 'aa', 'bb'
request.body = {'username' =>userName}.to_json
response = http.request request
#responseFromServer = response.body.to_s
end
newJson = JSON.parse(#responseFromServer)
status_msg = newJson['status']['status_msg']
if (status_msg == "Success")
return 'true'
end
return 'false'
end
It is method worked but he use OpenSSL::SSL::VERIFY_NONE. How to create method for send POST request without OpenSSL::SSL::VERIFY_NONE and PEM sertificate?
EDIT
SSL/HTTPS request
Update: There are some good reasons why this code example is bad. It introduces a potential security vulnerability if it's essential you use the server certificate to verify the identity of the server you're connecting to. There's a fix for the issue though!
require "net/https"
require "uri"
uri = URI.parse("https://secure.com/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
response.body
response.status
response["header-here"] # All headers are lowercase
SSL/HTTPS request with PEM certificate
require "net/https"
require "uri"
uri = URI.parse("https://secure.com/")
pem = File.read("/path/to/my.pem")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.cert = OpenSSL::X509::Certificate.new(pem)
http.key = OpenSSL::PKey::RSA.new(pem)
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Get.new(uri.request_uri)
My question: How to create POST method without PEM and OpenSSL::SSL::VERIFY_NONE?

This question is quite misleading, but I try my best to figure it out. Here is my advise:
Do you want to connect to a service that is only available through https and you do not care if the certificate is valid?
Then you can use :verify_mode => OpenSSL::SSL::VERIFY_NONE when initializing the Net::HTTP client.
You will have some kind of transport security, but you cannot be sure the server you are talking to is the one you think it is. You are vulnerable.
Do you want to connect to a service that is available both through https and http, and you do not care about transport security?
Then you should use the http://... endpoint.
Do you want to connect to a service and you care about transport security?
Then you should definitely use the https://... endpoint.
Do not override :verify_mode!
If you are getting certificate verification errors, make sure you have the correct Certificate Authority installed on your system.

Related

Net http connecting over plaintext even though SSL options are set

Using the net/http gem in Ruby, I am simply trying to connect over port 443/tcp using the following:
response = Net::HTTP.new(uri.host, uri.port, #proxy_ip, #proxy_port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE).start do |http|
request = Net::HTTP::Get.new(uri)
headers.each { |key, value| request[key] = value } unless headers.empty?
http.request(request)
end
However, the response is giving me an error showing that I'm connecting over port 80:
[12] pry(main)> response.body
=> "<html>\r\n<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>\r\n<body>\r\n<center><h1>400 Bad Request</h1></center>\r\n<center>The plain HTTP request was sent to HTTPS port</center>\r\n</body>\r\n</html>\r\n"
My initial way of connecting is this way:
response = Net::HTTP.start(uri.host, uri.port, #proxy_ip, #proxy_port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
http.request(request)
end
However, I needed to implement authentication for the proxy, and apparently I need to do this with the HTTP.new, so this code block was revised to try accommodating proxy authentication.
I have tried taking out #proxy_ip and #proxy_port, but this results in another error:
response = Net::HTTP.new(uri.host, uri.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE).start do |http|
request = Net::HTTP::Get.new(uri)
headers.each { |key, value| request[key] = value } unless headers.empty?
http.request(request)
end
error:
TypeError: Failed to open TCP connection to {:use_ssl=>true, :verify_mode=>0}:80 (no implicit conversion of Hash into String)
from /usr/local/rvm/rubies/ruby-2.7.6/lib/ruby/2.7.0/net/http.rb:960:in `initialize'
Caused by TypeError: no implicit conversion of Hash into String
from /usr/local/rvm/rubies/ruby-2.7.6/lib/ruby/2.7.0/net/http.rb:960:in `initialize'
My uri is just basically https://www.google.com/page?query=1&query=2
I'm just simply trying to make an HTTPS call while authenticating to a proxy (if one exists and is assigned in the environment variables).
The Net::HTTP.new constructor does not support SSL options directly. You have to add them later in the sequence. The signature for Net:HTTP.new is:
Net::HTTP.new(host, port, proxy_host, proxy_port, proxy_user, proxy_pass)
There is also a requirement to set use_ssl before start is called, otherwise the proxy setup will fail.
So with those things in mind, this should work:
http = Net::HTTP.new(host, port, proxy_host, proxy_port, proxy_user, proxy_pass)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
res = http.start { |connection|
request = Net::HTTP::Get.new(uri.request_uri)
headers.each { |key, value| request[key] = value } unless headers.empty?
connection.request(request)
}

Ruby - HTTPS get calls with headers

Have a query on making a https Get call with headers. I tried the following
uri = URI.parse("https:\\www.someurl.com")
req = Net::HTTP::Get.new(uri)
# Following is where I am adding the header
req['Auth'] = "Bearer" + #token
response = Net::HTTP.start(uri.host,uri.port) do |http|
request = Net::HTTP::Get.new uri.request_uri
http.request request
end
puts(response.body)
I see the following error
400 The plain HTTP request was sent to HTTPS port
I tried searching and what I have found is that Net::HTTP.get supports https calls but without headers.
The call that I am making is via API gateway, so I will have to add a token in the header.
Any help is much appreciated. Thanks in advance.
You need to use use_ssl: true.
uri = URI('https://secure.example.com/some_path?query=string')
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
request = Net::HTTP::Get.new(uri)
request['Authentication'] = "Bearer %s" % #token
http.request(request)
end

Microsoft Live authorization GET request returns Net::HTTPBadRequest 400

I am following Microsoft live connect API documentation to authorize my user to access onedrive. I am trying to stablish code flow authentication. I got the AUTHORIZATION_CODE as described. Now, I am trying to get the ACCESS_TOKEN with the help of that:
In Microsoft live connect API documentation, its said for getting ACCESS_TOKEN we need to provide a request such as,
POST https://login.live.com/oauth20_token.srf
Content-type: application/x-www-form-urlencoded
client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&client_secret=CLIENT_SECRET&
code=AUTHORIZATION_CODE&grant_type=authorization_code
I provided the same request using ruby and got a error:
#<Net::HTTPBadRequest 400 Bad Request readbody=true>
Then I found in microsoft forum, that the request is GET not POST.
so, I created a GET request in ruby as follow:
access_code =params["code"]
uri = URI.parse("https://login.live.com/oauth20_token.srf")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if uri.scheme == 'https'
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.read_timeout = 500
req = Net::HTTP::Get.new("https://login.live.com/oauth20_token.srf",
initheader = {'Content-Type' =>'application/x-www-form-urlencoded'})
data = URI.encode_www_form({'client_id'=> 'my_client_id' ,
'redirect_uri' =>'my_redirect_url',
'client_secret' =>'my_client_secret',
'code'=>access_code, 'grant_type' =>'authorization_code'})
req.body = data
res = http.start { |http| http.request(req) }
When I run this I am getting the same HTTPBadRequest 400 error.
Note: I have checked the values of CLIENT_ID,REDIRECT_URI,CLIENT_SECRET,AUTHORIZATION_CODE it's all perfect.
I regret seeing that forum to solve this problem and wasted my time.
actually POST request will do good in this situation as show in thier documentation.
This is how I got the response,
uri = URI.parse("https://login.live.com/oauth20_token.srf")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
req = Net::HTTP::Post.new("https://login.live.com/oauth20_token.srf")
req.content_type = "application/x-www-form-urlencoded"
data = URI.encode_www_form({'client_id'=> 'my_client_id' , 'redirect_uri' =>'my_redirect_ui', 'client_secret' =>'my_client_secret', 'code'=>access_code, 'grant_type' =>'authorization_code'})
req.body = data
response = http.request(req)

Ruby httpclient url

I am making a call to a webservice via HTTPClient ruby gem. The location doesn't matter, but let's say it is at: https://mywebservice.com/api/v1/accounts/login/
When I send a post request:
url = "https://mywebservice.com/api/v1/accounts/login/"
client = HTTPClient.new
client.post url
I get a 404 response, that the page was not found. I setup a proxy and checked out exactly what was being sent it seems like the gem is messing up the url, it actually sends the request to:
https://mywebservice.comhttps://mywebservice.com:443/api/v1/accounts/login/
I am completely lost, I have no why it is doing that. Does it have anything to do with the fact that it's https and I should handle https differently?
Thanks
Yes, if you are requesting a https url do this:
require 'net/http'
require 'net/https'
require 'uri'
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
#you need to set this field to true
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
response = http.request(request)
Here is a link that should help:
http://bibwild.wordpress.com/2012/04/30/httpclient-is-a-nice-http-client-forin-ruby/
You should post to an uri with a body of params. Something like
client.post "http://mysite.com:8080", data
where data is a hash with the required parameters for the page.
For instance:
data = {"var" => "var"}

curb post over ssl

how can you do a post over https using curb ruby gem?
This is how I do it over http to post a file to a server:
c = Curl::Easy.new("http://www.myserver.com/upload_messages")
c.multipart_form_post = true
post_field = Curl::PostField.content('fieldname', myfile)
c.http_post(post_field)
With net::http I would use use_ssl = true but how to do it with curb?
The post goes to an application running on heroku and the error I get now is:
Curl::Err::SSLCaertBadFile (Curl::Err::SSLCaertBadFile)
Thanks.
Have you tried c = Curl::Easy.new("https://www.myserver.com/upload_messages") (note the https instead of http on the url), cause in this example (https://github.com/taf2/curb/blob/master/samples/gmail.rb) from Curb's Github (that I suppose works, haven't tried it myself) they post to Gmail through https just doing that.
It seems that you have bad certificates and there should be option to trust unsigned.
require 'net/http'
require 'net/https'
require 'uri'
url = URI.parse 'https://myname:mypass#mail.google.com/'
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = (url.scheme == 'https')
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
Also try curb-fu gem. There you can make ssl post request like
form_data = { :color => 'red', :shape => 'sphere' }
response = CurbFu.post({:url => "https://example.com", :protocol => "https"}, form_data)

Resources