Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add server-side OTP and TOTP format validations #1251

Merged
merged 4 commits into from
Mar 28, 2017
Merged

Conversation

monfresh
Copy link
Contributor

Why: To minimize our attack surface and only accept allowed inputs,
which in this case is a string containing only numeric characters with
a length corresponding to the Devise.direct_otp_length and
Devise.otp_length settings, respectively.

@@ -13,6 +13,8 @@ def submit
attr_reader :code, :user

def valid_direct_otp_code?
code_length = Devise.direct_otp_length
return false unless code =~ /^\d{#{code_length}}$/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For defensive code like this, how about anchoring with \A and \Z as beginning and end of input (rather than line)?

This protects against nefarious inputs with newlines:

"aaaaa\n123456\naaaaaaaaa" =~ /^\d{6}$/
=> 6
"aaaaa\n123456\naaaaaaaaa" =~ /\A\d{6}\Z/
=> nil

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. That's what I meant to do but forgot to push. I thought there was a Rubocop setting that detects that, but it looks like it only looks for it when you use the Rails format validation.

@@ -13,6 +13,8 @@ def submit
attr_reader :user, :code

def valid_totp_code?
code_length = Devise.otp_length
return false unless code =~ /^\d{#{code_length}}$/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto re: anchoring

@monfresh
Copy link
Contributor Author

Updated and added a test with newlines. PTAL.

Copy link
Contributor

@zachmargolis zachmargolis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks for the fix

@@ -13,6 +13,8 @@ def submit
attr_reader :code, :user

def valid_direct_otp_code?
code_length = Devise.direct_otp_length
return false unless code =~ /\A\d{#{code_length}}\Z/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be helpful to name this regex for clarity?

context 'when the code is not exactly Devise.otp_length digits' do
it 'returns FormResponse with success: false' do
user = build_stubbed(:user)
codes = %W(123abc 1234567 abcdef aaaaa\n123456\naaaaaaaaa)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure what Devise.otp_length is...would it make sense to reference it here explicitly somehow? (my guess is that all of these are the wrong length but I am not sure)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean. I was trying to make this dynamic based on the Devise setting, in case it changes, but the wrong codes themselves are not derived from the setting, so I think in this case it would be clearer to just say 6 digits, and if the setting changes, we'll update the spec. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that makes sense. I was looking for more explicitness here around why these are not valid. If we label them as such, that would be great.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, got it. Commit coming up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this? 6cf0d70

**Why**: To minimize our attack surface and only accept allowed inputs,
which in this case is a string containing only numeric characters with
a length corresponding to the Devise.direct_otp_length and
Devise.otp_length settings, respectively.
@monfresh
Copy link
Contributor Author

How does this look, @jessieay: 41cdbac ?

user.authenticate_direct_otp(code)
end

def pattern_matching_otp_code_format
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 ⚡️

Copy link
Contributor

@jessieay jessieay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐶

@monfresh monfresh merged commit e35d846 into master Mar 28, 2017
@monfresh monfresh deleted the mb-field-validations branch March 28, 2017 18:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants