From 3723959b69f77d9d30e6bdf3c46802695c4d39eb Mon Sep 17 00:00:00 2001 From: Tobias Pfeifer Date: Sat, 25 Jun 2016 11:24:54 +0200 Subject: [PATCH] Akka-HTTP: basicAuthentication directive promotes insecure passwords #18858 (#20820) the Credentials Object used in the authenticateBasic Directive can be verified against passwords that are stored with a hashing function. By providing the same hashing function as an argument the clear-text password in the HttpCredentials will be hashed the same way prior to comparing against the stored secret. --- .../server/directives/SecurityDirectives.scala | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala index 7b845e3e15..3deba71abd 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala @@ -268,24 +268,35 @@ sealed trait Credentials object Credentials { case object Missing extends Credentials abstract case class Provided(identifier: String) extends Credentials { + + /** + * First applies the passed in `hasher` function to the received secret part of the Credentials + * and then safely compares the passed in `secret` with the hashed received secret. + * This method can be used if the secret is not stored in plain text. + * Use of this method instead of manual String equality testing is recommended in order to guard against timing attacks. + * + * See also [[EnhancedString#secure_==]], for more information. + */ + def verify(secret: String, hasher: String ⇒ String): Boolean + /** * Safely compares the passed in `secret` with the received secret part of the Credentials. * Use of this method instead of manual String equality testing is recommended in order to guard against timing attacks. * * See also [[EnhancedString#secure_==]], for more information. */ - def verify(secret: String): Boolean + def verify(secret: String): Boolean = verify(secret, x => x) } def apply(cred: Option[HttpCredentials]): Credentials = { cred match { case Some(BasicHttpCredentials(username, receivedSecret)) ⇒ new Credentials.Provided(username) { - def verify(secret: String): Boolean = secret secure_== receivedSecret + def verify(secret: String, hasher: String ⇒ String): Boolean = secret secure_== hasher(receivedSecret) } case Some(OAuth2BearerToken(token)) ⇒ new Credentials.Provided(token) { - def verify(secret: String): Boolean = secret secure_== token + def verify(secret: String, hasher: String ⇒ String): Boolean = secret secure_== hasher(token) } case Some(GenericHttpCredentials(scheme, token, params)) ⇒ throw new UnsupportedOperationException("cannot verify generic HTTP credentials")