Apache mod_session_dbd - 有人让它工作吗?

时间:2016-01-12 23:33:07

标签: apache httpd.conf

我正在将apache mod_auth_form从2.0.5升级到2.4。配置mod_session_dbd时遇到问题。需要帮忙!!

我对httpd.conf的配置 - 即使用户通过login.php验证后,也无法重定向到受保护的main / main.php页面。

代码:

CREATE TABLE `session` ( 
  `id` bigint unsigned      NOT NULL auto_increment, 
  `value`   varchar(512)    NOT NULL DEFAULT '', 
  `expiry`  bigint unsigned       NOT NULL DEFAULT 0, 
  `key`     varchar(256)    NOT NULL DEFAULT '', 
  primary key (id) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

DBDriver mysql 
DBDParams "host=127.0.0.1 port=3306 dbname=aware_db user=apache pass=dhishkhk" 
DBDMin  4 
DBDKeep 8 
DBDMax  20 
DBDExptime 300 
DBDPrepareSQL "select value from session where `key` = %s and (expiry = 0 or expiry > %lld)" selectsession 
DBDPrepareSQL "delete from session where `key` = %s" deletesession 
DBDPrepareSQL "insert into session (value, expiry, `key`) values (%s, %lld,  %s)" insertsession 
DBDPrepareSQL "update session set value = %s, expiry =  %lld, `key` = %s where `key` = %s" updatesession 

<Directory "/var/www/html/main"> 
        Options         -Indexes +FollowSymLinks 

        SSLRequireSSL 
    SetHandler form-login-handler 
    AuthFormLoginRequiredLocation /login.php 
    AuthFormLoginSuccessLocation /main/main.php 
    AuthFormProvider dbd 
AuthFormUsername uid 
AuthFormPassword password 

    AuthType form 
    AuthName "My Login" 
ErrorDocument 401 /login.php 
Session On 
#SessionDBDPerUser On 
SessionDBDCookieName session path=/; 
SessionDBDSelectLabel selectsession 
SessionDBDDeleteLabel deletesession 
SessionDBDInsertLabel insertsession 
SessionDBDUpdateLabel updatesession 

        SessionDBDCookieRemove Off 

        Require                 valid-user 

    ExpiresActive       On 
    ExpiresByType       application/x-java-jnlp-file    "now" 

</Directory>

我们编写自定义login.php脚本,该脚本在客户端首次访问主页面时调用。该脚本显示登录HTML表单,然后使用用户输入(uid和密码)对SQL用户DB以及LDAP用户帐户进行身份验证。验证uid /密码后,似乎mod_session能够设置“会话”cookie,但无法将会话存储到我创建的“会话”表中。我的理解是mod_session_dbd将匹配cookie中的“session”与会话数据库表中的信息(通过selectsession DBDPrepareSQL),并看到用户已经进行了认证,并让它转到主页,而不是登录。再次使用php,好像它没有经过身份验证(这是我上面的配置所发生的事情)。

mod_session_dbd的apache文档是最小的和不完整的,我无法在网络上的任何地方找到任何mod_session_dbd的工作示例,我可以用它作为参考。甚至不知道如何调试mod_session_dbd(LogLevel设置似乎没有得到痕迹)...任何帮助/建议将不胜感激!!

2 个答案:

答案 0 :(得分:2)

我认为这里的问题是你的外部登录脚本(不是mod_auth_form的“身份验证提供者”)无法直接与mod_auth_form通信认证成功。 (会话将仅在此之后插入到DB中)。然而,这种通信可以间接完成。请继续阅读...

我有类似的设置。我最终做的是让我的外部登录脚本模仿mod_session_dbd并在成功验证后自行插入数据库条目。之后,再次将页面重定向到同一保护区域。使用类似的东西(这是PHP代码)

header("Location: $toURL");

出于mod_session_dbd的目的,您的会话表必须至少有三列:uuid,session和expiry。 (但会话表也将作为mod_authn_dbd的会话密码表加倍。请参阅下面的讨论。)

只要你有以下指令,mod_auth_form就会在cookie中为你生成uuid。您的脚本可以读取cookie中的值(例如,从您的PHP脚本中)

SessionDBDCookieName uuid

mod_auth_form期望会话具有三个键值对,如下所示:

Realm-user=foo&Realm-pw=bar&expiry=1453231822000000

(到期是自Epoch以来的微秒数:即unix时间乘以1,000,000)

以上还假设您已将AuthName配置为“Realm”

AuthName "Realm"

现在,虽然登录脚本无法将成功验证结果传达给mod_auth_form,但它可以间接地通过为uuid的cookie与会话表的匹配行进行通信。

接下来,我将mod_auth_form配置为使用mod_authn_dbd作为“身份验证提供程序”。但是,后者不进行真正的身份验证(已经由登录脚本完成)。相反,它只是检查请求中是否存在会话(uuid的cookie以及会话表中的匹配行)。

所以,我所做的是在会话表中添加一个列(称为“session_pw”),然后配置mod_authn_dbd以使用以下查询进行密码查找(我使用的是MySQL):

AuthFormProvider dbd
AuthDBDUserPWQuery "SELECT session_pw FROM web_sessions WHERE uuid = %s and expiry>unix_timestamp()*1000000"

诀窍是要知道mod_authn_dbd期望什么,并且这个文档没有很好记录 - 它希望上述查询中的密码(session_pw)值已经被Apache允许的格式加密(参见{{3 }})。在我的情况下,我决定使用crypt,所以在会话表中,我的登录脚本实际上为session_pw插入了以下值

convert(encrypt(?, 'Cm') using ascii)

在哪里?绑定到我生成的会话密码(只是一个随机数) - 这个相同的值也必须放在上面显示的会话值中(即替换占位符“bar”为“Realm-的键值对” PW“)。

一旦mod_authn_dbd发现密码匹配,它就会让mod_auth_form知道,而后者会让请求进入受保护区域。 (所以我在这里做的是使用密码检查来测试会话是否存在)

我需要的另一个技巧是禁用会话插入并更新mod_session_dbd的查询(因为我的登录脚本现在进行插入)。我通过以下两个指令做到了这一点:

# we disable session insertion by mod_auth_form/mod_session_dbd -- login.php will insert the session
DBDPrepareSQL "select %s, %lld,  %s" insertsession
# we disable session update by mod_auth_form/mod_session_dbd
DBDPrepareSQL "select %s, %lld,  %s, %s" updatesession

最后,我想我可以分享会话表的架构,以防这可以帮助某人:

CREATE TABLE `web_sessions` (
  `id` int(11)  NOT NULL AUTO_INCREMENT,
  `u_name`      varchar(31) NOT NULL,   -- used for debugging only
  `session_pw`  varchar(256) NOT NULL,  -- encrypte by convert(encrypt(?, 'Cm') using ascii)
  `session`     varchar(256) NOT NULL,  -- mod_session_dbd's value
  `expiry`      bigint NOT NULL,        -- mod_session_dbd's expiry: microsecs since Epoch
  `uuid`        varchar(256) NOT NULL,  -- mod_session_dbd's key: uuid
  UNIQUE KEY `id` (`id`),
  UNIQUE KEY `uuid` (`uuid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

希望这有帮助!

答案 1 :(得分:0)

我本想在leeyuiwah的答案中添加评论,但是由于我的StackExchange得分还不够高,无法发表评论,因此我不得不将其添加到新答案中。

我按照leeyuiwah的回答(如果可以的话,这将是非常有价值的回答)进行了相当不错的尝试,并且花了更多的时间而不是承认这一点。第一次尝试是在2018年进行的,然后是2020年再次尝试,两次都是在Apache 2.4上进行的。因此,此答案的主要目的是警告其他人(在不太可能发生的其他人想要尝试此操作的情况下),以使他们不需要像我最终所做的那样冒险走下兔子洞。

我很高兴能证明这是行不通的错误,但是我认为很显然,如果这是可能的话,那么在2.4和2.5中似乎是不可能的(根据官方文档)。

在我看来,“抵消” mod_session_dbd文档中详细介绍的插入和更新查询,可能导致该模块无法执行其工作,可能是由于对插入数据的内置验证所致。如果数据库中的UUID /到期时间戳与模块要插入的时间戳不同,则该模块将不会使用它进行身份验证。另外,由于模块无法验证插入数据库的cookie的UUID值和有效期是否正确,因此它将在下一个请求时立即丢弃新的UUID。这意味着通过PHP脚本插入的UUID(如leeyuiwah的答案所述)是在模块丢弃新的UUID之后插入的。这似乎适合mod_session_dbd的官方文档指出:

由于先吃鸡还是先吃鸡蛋的局限性,每个用户会话不能用于存储来自mod_auth_form之类的模块中的身份验证凭据。

我认为出于安全原因这是故意的。