proper way to submit a form via https?

Hi, I am trying to find the 'recommended' way of doing this and have had little success so far. I have a login form. I want this to submit via https. What I have found I had to do was this:

<% form_for :user, :url =>{ :controller => :account, :action => :login, :only_path => false, :protocol => "https://" } do |form| %> (get login and password) <%end%>

This looks kind of crap and I am thinking there must be a nicer way! I am using the SSLRequirement plugin but that really doesn't work for forms as all you can do is a redirect, by which time it is too late.

Also, it would be nice if there was a way to only include the protocol attribute when I was in production mode as it is a hassle under dev!

Help!

Thanks.

Hi, I am trying to find the 'recommended' way of doing this and have had little success so far. I have a login form. I want this to submit via https. What I have found I had to do was this:

<% form_for :user, :url =>{ :controller => :account, :action => :login, :only_path => false, :protocol => "https://" } do |form| %> (get login and password) <%end%>

This looks kind of crap and I am thinking there must be a nicer way! I am using the SSLRequirement plugin but that really doesn't work for forms as all you can do is a redirect, by which time it is too late.

I'm not terribly experienced in this matter, but I believe that is the correct way.

Also, it would be nice if there was a way to only include the protocol attribute when I was in production mode as it is a hassle under dev!

You can try something like this in application.rb

  def require_ssl     if request.ssl? || local_request?       return true     else       redirect_to :protocol => "https://" and return false     end   end

which says if the request is already ssl, or it's local, return true. Then in your controllers,

before_filter :require_ssl

it works for me.

Peace, Phillip

How about setting :only_path => true ? That way, the forms action attribute will contain only the relative url to the target controller which implies https given that the display of the form happened through https.

You can try something like this in application.rb

        def require_ssl                 if request.ssl? || local_request?                         return true                 else                         redirect_to :protocol => "https://" and return false                 end         end

which says if the request is already ssl, or it's local, return true. Then in your controllers,

before_filter :require_ssl

it works for me.

Peace, Phillip

But won't the end result of this be that the form will be submitted via http (ergo having everything transmitted in clear text) and then have it go 'whoops, this should be https' and redirect to https? This method is what ssl_requirement does, which is good for secure pages, just not secure form submissions.

Maybe I am doing something wrong, but, with :only_path => false I get: <form action="https://localhost:3002/es/account/signup&quot; method="post">

but with it true I get: <form action="/es/account/signup" method="post">

Which looks like it is ignoring the protocol completely! (I am running under rails 1.2.5 btw)

I am not displaying the form via https, as really there is no need. The information on login (and registration) is not sensitive - just the stuff the user fills in and submits.

If your initial submission is to https, then you shouldn't have a problem. So in your view, if you have as the action of the form

action="https://some_url"

then it should be encrypted on the way. I actually wrestled with this some and decided to go the way of PayPal. If you go to http://www.paypal.com, you are immediately redirected to https://www.paypal.com. I found that it's easier to just run the whole site in https than switch back and forth. And with my site being more an online application than a "web site", it makes more sense.

Peace, Phillip

Maybe I am doing something wrong, but, with :only_path => false I get: <form action="https://localhost:3002/es/account/signup&quot; method="post">

but with it true I get: <form action="/es/account/signup" method="post">

This is correct. A relative path infers the missing pieces from the current documents url. Thus it's not "ignoring" the protocol, but using the very same which you used to display your form.

I am not displaying the form via https, as really there is no need. The information on login (and registration) is not sensitive - just the stuff the user fills in and submits.

Yes but if you display the form via https (maybe even enforcing that with ssl_requirement), the form can infer the protocol. Try installing the Firebug and TamperData extensions for Firefox to play around with this stuff and see how the forms action is derived from the action attribute and the documents url.

SSL Requirement if fine when the container page is already secure.

I normally use Secure Actions:

    http://agilewebdevelopment.com/plugins/secure_actions

which allows declaration of secure actions as well and hooks into URL generation to get the right protocol. I blogged some details about the plugin here:

     Advogato: Blog for fxn

-- fxn

Along the same lines of this thread, I have a secure online form that I am using to create and save accounts. I'm using SSL to process the new accounts (ultimately we'll be accepting credit cards). My experience with using SSL is practically nil (at least in Rails). So the account creation works locally AND in production when I refrain from using SSL. However when I go through the https:// URL, the form does not process, doesn't provide any error messages, and simply displays the "new" action again as if the data errorred out. I am using the ssl_required plugin, too. All to no avail.

I have a temporary Comodo certified certificate and I do not get the invalid certificate prompt at our production URL. It feels like I might just be missing a detail pertaining to the SSL certificate or whatnot that is a quick fix. At least I hope that's the problem. If you have any thoughts, feel free to share!

Thanks,

-e

But if I have/want a login widget at the top of every page the only nice way to get that working with this method is to have every page ssl'd. Which is ridiculous.

What I am doing now is this:   <% unless RAILS_ENV == 'production'       url_options = { :controller => :account, :action => :do_login }     else       url_options = { :controller => :account, :action => :do_login, :protocol => 'https://', :only_path => false }     end %>

It's a hack, but it works.

I decided to write this:   def secure_form_for(record_or_name_or_array, *args, &proc)     unless RAILS_ENV == 'production'       url_options = {}     else       url_options = {:protocol => 'https://', :only_path => false }     end

    options = args.last.is_a?(Hash) ? args.pop : {}     options = url_options.merge options

    return form_for(record_or_name_or_array, options, &proc)   end

Anyone think this is crazy? Seems to work so far.

Actually, that didn't quite work. This does:   def secure_form_for(record_or_name_or_array, *args, &proc)     unless RAILS_ENV == 'production'       url_options = {}     else       url_options = {:protocol => 'https://', :only_path => false }     end

    options = args.last.is_a?(Hash) ? args.pop : {}     if !options[:url].nil?       options[:url] = url_options.merge options[:url]     else       options[:url] = url_options     end

    return form_for(record_or_name_or_array, options, &proc)   end