Zabbix怎么搞一个永不过期的session
2017-01-19
zabbix的session会隔一段时间就不可用了,查一下原因
zabbix的session什么时候过期?
看zabbix的数据库,session相关的表有两个:
mysql> desc users;
+----------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------------+------+-----+---------+-------+
| userid | bigint(20) unsigned | NO | PRI | NULL | |
| alias | varchar(100) | NO | MUL | | |
| name | varchar(100) | NO | | | |
| surname | varchar(100) | NO | | | |
| passwd | char(32) | NO | | | |
| url | varchar(255) | NO | | | |
| autologin | int(11) | NO | | 0 | |
| autologout | int(11) | NO | | 900 | |
| lang | varchar(5) | NO | | en_GB | |
| refresh | int(11) | NO | | 30 | |
| type | int(11) | NO | | 0 | |
| theme | varchar(128) | NO | | default | |
| attempt_failed | int(11) | NO | | 0 | |
| attempt_ip | varchar(39) | NO | | | |
| attempt_clock | int(11) | NO | | 0 | |
| rows_per_page | int(11) | NO | | 50 | |
+----------------+---------------------+------+-----+---------+-------+
mysql> desc sessions;
+------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+-------+
| sessionid | varchar(32) | NO | PRI | | |
| userid | bigint(20) unsigned | NO | MUL | NULL | |
| lastaccess | int(11) | NO | | 0 | |
| status | int(11) | NO | | 0 | |
+------------+---------------------+------+-----+---------+-------+
登录时验证sql为
$userInfo = DBfetch(DBselect(
'SELECT u.userid,u.autologout,s.lastaccess'.
' FROM sessions s,users u'.
' WHERE s.sessionid='.zbx_dbstr($sessionid).
' AND s.status='.ZBX_SESSION_ACTIVE.
' AND s.userid=u.userid'.
' AND (s.lastaccess+u.autologout>'.$time.' OR u.autologout=0)'
));
sessions中的lastaccess为上一次登录的时间,status有两个值
define('ZBX_SESSION_ACTIVE', 0);
define('ZBX_SESSION_PASSIVE', 1);
passive是每次logout的时候把status置为passive,然后下一次删除。
所以session并没有一个过期的标志,那么session为什么会过期?
那肯定是有定时任务喽。
搜索代码delete from session,出现下面的
rc = DBexecute("delete from sessions where lastaccess<%d", now - SEC_PER_DAY * hk_config.sessions);
这个会把小于now - SEC_PER_DAY * hk_config.sessions的都干掉,顾名思义,now就是现在的时间,SEC_PER_DAY是一天多少秒,那么看看hk_config.sessions是多少就行了。
搜索代码hk.sessions,出现下面的
config->config->hk.sessions = 365;
会自动删除一年未登录的session
zabbix常规登陆验证流程:
分析./include/classes/user/CWebUser.php中的login和logout可以了解到zabbix的常规验证流程。 主要逻辑如下:
login
- 查询出对应用户名密码的user对象
- 检查该用户登陆尝试次数是否超出限制
- 根据查询的userid验证用户权限,将页面是否允许访问存入guiAccess
- 登陆方式选择(ldap、数据库)
- 开始新的session: 生成sessionId,将(sessionId、userid、当前时间、激活状态)插入数据库
- 根据第3步的guiAccess判断是否结束并抛出异常
- 成功登陆后,清除访客的session
- 将新的sessionId存入cookie
- 对该次用户登录做审计
logout
- 从cookie里得到sessionId
- 从数据库里删除该登出用户对应的所有状态为PASSIVE的session记录
- 将cookie中得到的这个sessionId对应的session记录的状态修改为PASSIVE
- 从cookie里删除该sessionId
API验证流程
包括api_jsonrpc.php的几乎每一个zabbix的展示页面或者api的php代码都会在开头包含一个config.inc.php,且并无其他验证相关代码存在,config.inc.php中只有一行主要代码Z::getInstance()->run(),追踪到这个run函数里,就能找到疑似的验证流程入口$this->authenticateUser()。 该函数位于 ./include/classes/core/ZBase.php 中。
checkAuthentication
ZBase.php中的函数,是对./include/classes/user/CWebUser.php中同名函数的封装,CWebUser.php中的checkAuthentication又是对zabbix API即./include/classes/api/services/CUser.php中的同名函数的封装。
具体流程如下:
- 从cookie中取出zbx_sessionid的值存入sessionId
- 如果该sessionId不为空,根据这个sessionId查询出对应的用户userid、autologout字段和处于ACTIVE状态session的lastaccess字段,如果sessionId为空,以访客模式调用login函数并得到新的sessionId,该sessionId对应的GUEST特殊用户将不能通过后面的权限认证
- 如果步骤2没有查出记录,那么会报错Session terminated, re-login, please
- 调用check_perm2system检查该用户的权限,若有问题,报错No permissions for system access
- 如果查出的记录的autologout > 0, 删除数据库中对应用户的过期的session
- 更新数据库中当前sessionId和userId对应的session记录的最近访问是时间(lassaccess)字段
- 检查该用户的页面访问权限(检查gui_access,与login流程的验证guiAccess一样)
- 将userid,sessionid,gui_access存入data变量中
- 如果gui_access为GROUP_GUI_ACCESS_DISABLED,即禁用,抛异常,退出。
- 将sessionId保存到cookie中
- 用sessionId为API设置验证令牌
分析得出结论,如果要实现在任何环境下的一次URL跳转都能成功以管理员的权限进入zabbix,关键在于以上流程的第2步,不能以访客模式进入zabbix,即需要让sessionId不为空且可用,自然得出的办法就是,提前保存好一个可用的sessionId到cookie中。
多番测试后,证实了以上方案是可行的,于是,实施方案如下:
手动在zabbix增加一个session记录,每次直接请求URL的时候,先调用一个自定义php,存入这个session的id,再继续访问,bingo!