For *real* improvement, wouldn't storing in socache be
the optimal method?

On Jan 1, 2013, at 3:16 PM, s...@apache.org wrote:

> Author: sf
> Date: Tue Jan  1 20:16:30 2013
> New Revision: 1427548
> 
> URL: http://svn.apache.org/viewvc?rev=1427548&view=rev
> Log:
> Add some caching for password hash validation.
> 
> Password hash functions must be expensive in order to be secure. But
> if they have to be re-evaluated for every request, performance
> suffers.
> 
> As a minimal remedy, cache the most recent result for every
> connection. This gives a great performance boost if a web browser
> does many requests on the same connection with the same
> user+password.  In principle, this may keep the plain text password
> around longer than before. But in practice, there won't be much
> difference since user+password can already remain in some unused
> data bucket for longer than the request duration.
> 
> A proper solution still needs to be found for connections from
> proxies which may carry requests for many different users.
> 
> While it currently only requires the conn_rec, the new
> ap_password_validate() function takes username and request_rec to
> allow future extensions, like detection of brute-force attempts.
> 
> 
> Modified:
>    httpd/httpd/trunk/CHANGES
>    httpd/httpd/trunk/include/ap_mmn.h
>    httpd/httpd/trunk/include/httpd.h
>    httpd/httpd/trunk/modules/aaa/mod_authn_dbd.c
>    httpd/httpd/trunk/modules/aaa/mod_authn_dbm.c
>    httpd/httpd/trunk/modules/aaa/mod_authn_file.c
>    httpd/httpd/trunk/modules/aaa/mod_authn_socache.c
>    httpd/httpd/trunk/server/util.c
> 
> Modified: httpd/httpd/trunk/CHANGES
> URL: 
> http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1427548&r1=1427547&r2=1427548&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/CHANGES [utf-8] (original)
> +++ httpd/httpd/trunk/CHANGES [utf-8] Tue Jan  1 20:16:30 2013
> @@ -1,6 +1,11 @@
>                                                          -*- coding: utf-8 -*-
> Changes with Apache 2.5.0
> 
> +  *) mod_authn_file, mod_authn_dbd, mod_authn_dbm, mod_authn_socache:
> +     Cache the result of the most recent password hash verification for every
> +     keep-alive connection. This saves some expensive calculations.
> +     [Stefan Fritsch]
> +
>   *) http: Remove support for Request-Range header sent by Navigator 2-3 and
>      MSIE 3. [Stefan Fritsch]
> 
> 
> Modified: httpd/httpd/trunk/include/ap_mmn.h
> URL: 
> http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_mmn.h?rev=1427548&r1=1427547&r2=1427548&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/include/ap_mmn.h (original)
> +++ httpd/httpd/trunk/include/ap_mmn.h Tue Jan  1 20:16:30 2013
> @@ -412,6 +412,7 @@
>  *                         core_server_config again, add http09_enable
>  * 20121222.1 (2.5.0-dev)  Add http_conformance to core_server_config,
>  *                         add ap_has_cntrl()
> + * 20121222.2 (2.5.0-dev)  Add ap_password_validate()
>  */
> 
> #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
> @@ -419,7 +420,7 @@
> #ifndef MODULE_MAGIC_NUMBER_MAJOR
> #define MODULE_MAGIC_NUMBER_MAJOR 20121222
> #endif
> -#define MODULE_MAGIC_NUMBER_MINOR 1                   /* 0...n */
> +#define MODULE_MAGIC_NUMBER_MINOR 2                   /* 0...n */
> 
> /**
>  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
> 
> Modified: httpd/httpd/trunk/include/httpd.h
> URL: 
> http://svn.apache.org/viewvc/httpd/httpd/trunk/include/httpd.h?rev=1427548&r1=1427547&r2=1427548&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/include/httpd.h (original)
> +++ httpd/httpd/trunk/include/httpd.h Tue Jan  1 20:16:30 2013
> @@ -2274,6 +2274,24 @@ AP_DECLARE(void) ap_bin2hex(const void *
> AP_DECLARE(int) ap_has_cntrl(const char *str)
>                 AP_FN_ATTR_NONNULL_ALL;
> 
> +/**
> + * Wrapper for @a apr_password_validate() to cache expensive calculations
> + * @param r the current request
> + * @param username username of the user
> + * @param passwd password string
> + * @param hash hash string to be passwd to @a apr_password_validate()
> + * @return APR_SUCCESS if passwords match, APR_EMISMATCH or error otherwise
> + * @note Currently, ap_password_validate() only caches the result of the
> + *       most recent call with the same connection as @a r.
> + *       In the future, it may also do rate-limiting against brute-force
> + *       attacks.
> + */
> +AP_DECLARE(apr_status_t) ap_password_validate(request_rec *r,
> +                                              const char *username,
> +                                              const char *passwd,
> +                                              const char *hash);
> +
> +
> #define AP_NORESTART APR_OS_START_USEERR + 1
> 
> #ifdef __cplusplus
> 
> Modified: httpd/httpd/trunk/modules/aaa/mod_authn_dbd.c
> URL: 
> http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/aaa/mod_authn_dbd.c?rev=1427548&r1=1427547&r2=1427548&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/modules/aaa/mod_authn_dbd.c (original)
> +++ httpd/httpd/trunk/modules/aaa/mod_authn_dbd.c Tue Jan  1 20:16:30 2013
> @@ -179,7 +179,7 @@ static authn_status authn_dbd_password(r
>     }
>     AUTHN_CACHE_STORE(r, user, NULL, dbd_password);
> 
> -    rv = apr_password_validate(password, dbd_password);
> +    rv = ap_password_validate(r, user, password, dbd_password);
> 
>     if (rv != APR_SUCCESS) {
>         return AUTH_DENIED;
> 
> Modified: httpd/httpd/trunk/modules/aaa/mod_authn_dbm.c
> URL: 
> http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/aaa/mod_authn_dbm.c?rev=1427548&r1=1427547&r2=1427548&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/modules/aaa/mod_authn_dbm.c (original)
> +++ httpd/httpd/trunk/modules/aaa/mod_authn_dbm.c Tue Jan  1 20:16:30 2013
> @@ -27,7 +27,6 @@
> #include "apr_want.h"
> #include "apr_strings.h"
> #include "apr_dbm.h"
> -#include "apr_md5.h"        /* for apr_password_validate */
> 
> #include "ap_provider.h"
> #include "httpd.h"
> @@ -144,7 +143,7 @@ static authn_status check_dbm_pw(request
>     }
>     AUTHN_CACHE_STORE(r, user, NULL, dbm_password);
> 
> -    rv = apr_password_validate(password, dbm_password);
> +    rv = ap_password_validate(r, user, password, dbm_password);
> 
>     if (rv != APR_SUCCESS) {
>         return AUTH_DENIED;
> 
> Modified: httpd/httpd/trunk/modules/aaa/mod_authn_file.c
> URL: 
> http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/aaa/mod_authn_file.c?rev=1427548&r1=1427547&r2=1427548&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/modules/aaa/mod_authn_file.c (original)
> +++ httpd/httpd/trunk/modules/aaa/mod_authn_file.c Tue Jan  1 20:16:30 2013
> @@ -15,7 +15,6 @@
>  */
> 
> #include "apr_strings.h"
> -#include "apr_md5.h"            /* for apr_password_validate */
> 
> #include "ap_config.h"
> #include "ap_provider.h"
> @@ -112,7 +111,7 @@ static authn_status check_password(reque
>     }
>     AUTHN_CACHE_STORE(r, user, NULL, file_password);
> 
> -    status = apr_password_validate(password, file_password);
> +    status = ap_password_validate(r, user, password, file_password);
>     if (status != APR_SUCCESS) {
>         return AUTH_DENIED;
>     }
> 
> Modified: httpd/httpd/trunk/modules/aaa/mod_authn_socache.c
> URL: 
> http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/aaa/mod_authn_socache.c?rev=1427548&r1=1427547&r2=1427548&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/modules/aaa/mod_authn_socache.c (original)
> +++ httpd/httpd/trunk/modules/aaa/mod_authn_socache.c Tue Jan  1 20:16:30 2013
> @@ -15,7 +15,6 @@
>  */
> 
> #include "apr_strings.h"
> -#include "apr_md5.h"            /* for apr_password_validate */
> 
> #include "ap_config.h"
> #include "ap_provider.h"
> @@ -375,7 +374,7 @@ static authn_status check_password(reque
>         return AUTH_USER_NOT_FOUND;
>     }
> 
> -    rv = apr_password_validate(password, (char*) val);
> +    rv = ap_password_validate(r, user, password, (char*) val);
>     if (rv != APR_SUCCESS) {
>         return AUTH_DENIED;
>     }
> 
> Modified: httpd/httpd/trunk/server/util.c
> URL: 
> http://svn.apache.org/viewvc/httpd/httpd/trunk/server/util.c?rev=1427548&r1=1427547&r2=1427548&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/server/util.c (original)
> +++ httpd/httpd/trunk/server/util.c Tue Jan  1 20:16:30 2013
> @@ -30,6 +30,7 @@
> #include "apr.h"
> #include "apr_strings.h"
> #include "apr_lib.h"
> +#include "apr_md5.h"            /* for apr_password_validate */
> 
> #define APR_WANT_STDIO
> #define APR_WANT_STRFUNC
> @@ -2896,3 +2897,42 @@ AP_DECLARE(void) ap_get_loadavg(ap_loada
>     }
> #endif
> }
> +
> +static const char * const pw_cache_note_name = "conn_cache_note";
> +struct pw_cache {
> +    /* varbuf contains concatenated password and hash */
> +    struct ap_varbuf vb;
> +    apr_size_t pwlen;
> +    apr_status_t result;
> +};
> +
> +AP_DECLARE(apr_status_t) ap_password_validate(request_rec *r,
> +                                              const char *username,
> +                                              const char *passwd,
> +                                              const char *hash)
> +{
> +    struct pw_cache *cache;
> +    apr_size_t hashlen;
> +
> +    cache = (struct pw_cache *)apr_table_get(r->connection->notes, 
> pw_cache_note_name);
> +    if (cache != NULL) {
> +        if (strncmp(passwd, cache->vb.buf, cache->pwlen) == 0
> +            && strcmp(hash, cache->vb.buf + cache->pwlen) == 0) {
> +            return cache->result;
> +        }
> +        /* make ap_varbuf_grow below not copy the old data */
> +        cache->vb.strlen = 0;
> +    }
> +    else {
> +        cache = apr_palloc(r->connection->pool, sizeof(struct pw_cache));
> +        ap_varbuf_init(r->connection->pool, &cache->vb, 0);
> +        apr_table_setn(r->connection->notes, pw_cache_note_name, (void 
> *)cache);
> +    }
> +    cache->pwlen = strlen(passwd);
> +    hashlen = strlen(hash);
> +    ap_varbuf_grow(&cache->vb, cache->pwlen + hashlen + 1);
> +    memcpy(cache->vb.buf, passwd, cache->pwlen);
> +    memcpy(cache->vb.buf + cache->pwlen, hash, hashlen + 1);
> +    cache->result = apr_password_validate(passwd, hash);
> +    return cache->result;
> +}
> 
> 

Reply via email to