我正在将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设置似乎没有得到痕迹)...任何帮助/建议将不胜感激!!
答案 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之类的模块中的身份验证凭据。
我认为出于安全原因这是故意的。