2

With rail's simple_form gem:

If I have = f.input :password, :required => true then whenever I submit the form and it contains errors, my input for the password is gone on page reload. If I use = f.input :password, :required => true, :as => :text it all works like expected, so clearly there's a different handling for password fields.

How to remember values for password fields?

EDIT: some people don't seem to understand that I'm talking about redisplaying the same form with values previously entered. This question has NOTHING to do with database, in fact nothing is even saved in the database in that scenario. For the PHP people, this is the equivalent of <input name="pass" type="password" value="<?= $_POST['pass']; ?>">

Silex
  • 1,707
  • 17
  • 24
  • 1
    u shouldnt remember values for password or password confirmation fields. they should be filled explicitly each time. – Prasad Surase Oct 28 '13 at 09:45
  • The answer to my problem still interests me. Anyway, why shouldn't I remember values for password fields? – Silex Oct 28 '13 at 09:47
  • 1
    passwords are not stored in browser since its sensitive information. see http://stackoverflow.com/questions/3040731/should-autocomplete-off-be-used-for-all-sensitive-fields – Prasad Surase Oct 28 '13 at 09:55
  • @prasad.surase I thought autocomplete allowed a browser to present a dropdown with previously entered values so that the user can select one. Surely a different mechanism preserves form data when there are validation errors? In that case, most inputs will still have the exact same data as what the user just typed in, regardless of what data they have typed into the form previously. – Rupert Madden-Abbott Oct 28 '13 at 10:08
  • 1
    @prasad.surase: the top answer in your paste shows that a lot of people don't like it when you try to be smarter than them. IMHO this is one of the things that should be configured in the browser by the user (e.g tick some "[x] don't remember any password [x] empty form password fields"). Personnaly I hate retyping the same password over and over again until there's no more errors in the form, gives me much more odds of doing a typo in the password. – Silex Oct 28 '13 at 10:18
  • If you store the users password in plaintext so that you can return it to the form after validation your system is insecure. Passwords should NEVER be remembered in plaintext by the system they unlock! – Matt Oct 28 '13 at 10:27
  • @Matt: who said anything about storing them? It's just when failing validation! When creating an account and validation fails, I still know what password was sent through the HTTP post headers. In the database I have no clue what password they used, as only a hash is stored. – Silex Oct 28 '13 at 13:08
  • If it persists to the next call, you stored it. It's just a really bad idea, why not stick to the standards that every other website finds acceptable? – Matt Oct 28 '13 at 13:57
  • @Matt: I'm sorry I don't get it. `` is ok but as soon as you change the field type from `text` to `password` it isn't? Can you explain why? – Silex Oct 28 '13 at 15:29
  • @Matt If you store it in memory in plaintext, only until the next call, where you return it to the user, why is that such a problem? They sent it in plaintext in the original HTTP post call, so storing it for a microsecond before you return it in a similar HTTP call, wouldn't be much different? I presume the server memory is flushed pretty often, if not then you can do a manual flush. – Magne Jan 27 '15 at 15:54

3 Answers3

6

About the question, the answer is to use input_html: { value: @user_password }

Like this:

<%= f.input :password, :required => true, input_html: { value: @user_password } %>
<%= f.input :password_confirmation, :required => true, input_html: { value: @user_password } %>

About the secondary topic on restoring password value, after investiguation it's really more like an extra little security bump. The real security is done by using HTTPS, or by having the password hashing done client side with javascript that way the server doesn't even knows about the password.

For examples, even websites as big as https://github.com/join seems to do it the way I'm doing it (fill the password but input an invalid email and see the password being filled as a plain HTML value element).

The corresponding route and controller can look like:

routes.rb :

devise_for :users, :controllers => {registrations: 'users/registrations' }

registrations_controller.rb :

class Users::RegistrationsController < Devise::RegistrationsController
  # build_resource is called inside the new and create methods
  def build_resource(*args)
    if params[:user]
      # So that the password isn't blanked out when the other validations fail. User shouldn't have to retype the password.
      @user_password = params[:user][:password]
    end
    super
  end
end
Magne
  • 16,401
  • 10
  • 68
  • 88
Silex
  • 1,707
  • 17
  • 24
  • 1
    as of January 27, 2015, github doesn't seem to do it the way you suggested. Github forces you to retype the password and confirmation after you've sent a form that invalidates. – Magne Jan 27 '15 at 15:49
4

This is not a SimpleForm behavior, it's in the way Rails treats inputs of password type (see http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-password_field).

SimpleForm uses the rails password_field method which defaults to a blank value. The API clearly says to set the value through options parameter.

2

I don't know exactly how Rails handles this but if I were writing this manually, say in PHP, then to get entered form data back into the form, after a validation error, then I would have to render the data back into each input's value attribute.

There is nothing technically preventing me from doing that with password inputs but it would mean that I would have to pass their own password back to them, in plain text. This, I think, is a deal breaker, because it provides another opportunity for the password to get intercepted.

After reading around on this subject, it seems that a number of people consider this to also be a form of "storing" the password in plain text which is clearly bad. However, it is not at all clear to me why it is considered "storing" a password as the server clearly would not need to store the plain text password anywhere, beyond in the very same variable that was used to receive the plain text password in the first place. However, it may be that they mean that the password is stored in the HTTP response which is then essentially the same concern that I raise above.

Another reason I have seen is that to insert the password back into the password input would require using the value attribute. Whilst this would obscure the password in the rendered input, the password would be visible when inspecting the source using e.g. Firebug. For me, this is a non-issue because it is trivial to turn the type of an input from password to text and reveal the password anyway, or just use JS. It is absolutely incorrect to think that a password field provides much built in security beyond obscuring the password visually.

What you could do is:

  1. Hash the password (presuming it, itself, passes validation) and store that even if the rest of the data fails validation
  2. Disable the password fields on the returned form or otherwise indicate to the user that the password they have submitted has been accepted but the rest of the form data needs to be fixed.
  3. Optionally provide a way for the user to reactivate the password fields, if they decide they want a different password.
  4. Run a cron task that regularly cleans the database of any orphaned password entries where a user, for whatever reason, didn't bother to continue signing up but did submit the form with errors, at least once.

I can't immediately see how that would compromise security in any way.

Another approach would be to have a multi-step form and have the password and password confirmation inputs on their own, in the last step. That way, you can ensure the rest of the data is valid by the time the user has reached the password stage and if they have any errors in their passwords (for example the password and password confirmation do not match) then you could argue it is reasonable to then render both fields blank as the user won't be able to easily fix the problem with the passwords obscured.

Rupert Madden-Abbott
  • 12,899
  • 14
  • 59
  • 74
  • About security: they already gave me their password in plain text. This security reasoning really looks like hair splitting to me. I agree it reduces *a little* security issues but honestly, if someone can intercept the website response and play a man-in-the-middle you have far bigger problems already. Also the question is not about how to technically do what I'm asking in HTML, but how to configure the `simple_form` plugin behavior about password fields. – Silex Oct 28 '13 at 13:04
  • 1
    @Silex I do agree that this does seem like hair splitting and with your answer that HTTPS does already handle these concerns. However, after looking around I am surprised to find that I can find very little on this topic. I'm sure you'll agree that it is very common for password fields to not be filled out after validation (even if some big sites do it) and even simple form, itself, requires a workaround. I wonder if there really is a good reason for this. I see you opened up an issue on simple form and I wonder if there isn't a good reason why they shouldn't change the built in behaviour? – Rupert Madden-Abbott Nov 06 '13 at 16:45
  • Yeah, given the little impact this has on security _risks_, I assume this is more in the "good practice" category than in the "must do or be vulnerable" one. I'd be happy to be proven wrong :) – Silex Nov 08 '13 at 13:12