Skip to content

Commit

Permalink
Merge pull request #83 from jazeee/fix-issue-81-2
Browse files Browse the repository at this point in the history
Add delay when accessing unauthorized ReST endpoints
  • Loading branch information
kahmali committed Jun 17, 2015
2 parents 18ce680 + 8fe7e6f commit a94aa48
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Update default auth endpoints to match current Accounts token storage (see #79)
- Return "Unauthorized" for failed authentication
- To match Meteor, store password token as `hashedToken`
- When logging in with bad credentials, randomly delay the response (See #81)
- Add unit tests for authentication


Expand Down
15 changes: 13 additions & 2 deletions lib/route.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,19 @@ class @Route
# Send response
endpointContext.response.writeHead statusCode, headers
endpointContext.response.write body
endpointContext.response.end()

if statusCode in [401, 403]
# Hackers can measure the response time to determine things like whether the 401 response was
# caused by bad user id vs bad password.
# In doing so, they can first scan for valid user ids regardless of valid passwords.
# Delay by a random amount to reduce the ability for a hacker to determine the response time.
# See https://www.owasp.org/index.php/Blocking_Brute_Force_Attacks#Finding_Other_Countermeasures
# See https://en.wikipedia.org/wiki/Timing_attack
minimumDelayInMilliseconds = 500
randomMultiplierBetweenOneAndTwo = 1 + Math.random()
delayInMilliseconds = minimumDelayInMilliseconds * randomMultiplierBetweenOneAndTwo
Meteor.setTimeout endpointContext.response.end, delayInMilliseconds
else
endpointContext.response.end()

###
Return the object with all of the keys converted to lowercase
Expand Down
13 changes: 10 additions & 3 deletions test/authentication_tests.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ Meteor.startup ->

next()

it 'should not allow a user with wrong password to login', (test, next) ->
it 'should not allow a user with wrong password to login and should respond after 500 msec', (test, next) ->
# This test should take 500 msec or more. To speed up testing, these two tests have been combined.
startTime = new Date()
HTTP.post Meteor.absoluteUrl('/api/v1/login'), {
data:
user: username
Expand All @@ -59,6 +61,8 @@ Meteor.startup ->
response = JSON.parse result.content
test.equal result.statusCode, 403
test.equal response.status, 'error'
durationInMilliseconds = new Date() - startTime
test.isTrue durationInMilliseconds >= 500

next()

Expand All @@ -73,10 +77,11 @@ Meteor.startup ->
test.equal response.status, 'success'
next()

it 'should remove the logout token after logging out', (test, next) ->
it 'should remove the logout token after logging out and should respond after 500 msec', (test, next) ->
Restivus.addRoute 'prevent-access-after-logout', {authRequired: true},
get: -> true

# This test should take 500 msec or more. To speed up testing, these two tests have been combined.
startTime = new Date()
HTTP.get Meteor.absoluteUrl('/api/v1/prevent-access-after-logout'), {
headers:
'X-User-Id': userId
Expand All @@ -86,6 +91,8 @@ Meteor.startup ->
test.isTrue error
test.equal result.statusCode, 401
test.equal response.status, 'error'
durationInMilliseconds = new Date() - startTime
test.isTrue durationInMilliseconds >= 500
next()

it 'should allow a second logged in user to logout', (test, next) ->
Expand Down

0 comments on commit a94aa48

Please sign in to comment.