I'm thinking about making information from Zabbix available for external mobile devices .
For security reasons I want to allow only limited access via the API.
As quick shot I modified the API to achieve the following criteria:
I'm not familiar with PHP at all and want to ask you experienced PHP programmes if the following code is secure in terms of programming and reasonable for the intended use case.
For security reasons I want to allow only limited access via the API.
As quick shot I modified the API to achieve the following criteria:
- Honor the following criteria only if API is called from IP indicating external access
- Limit access to Zabbix users with specific user name characteristic (E.g. user name has to end with '.mobile')
- Allow only a selection of API methods
- Rewrite params (Eg. limit result set, regardless if and what limit is initially set in request)
- Log an audit trail containing all params used for requests.
I'm not familiar with PHP at all and want to ask you experienced PHP programmes if the following code is secure in terms of programming and reasonable for the intended use case.
Code:
--- SNIP /usr/share/zabbix/api_jsonrpc.php ---
$data = $http_request->body();
if(preg_match('/^192.0.43.10/', $_SERVER['REMOTE_ADDR'])){
function wlog($fh, $msg){
$log_str = date(DATE_ISO8601) . " " . $msg . "\n";
fwrite($fh, $log_str);
}
$jsonrpc_audit_log = "/var/log/zabbix/zabbix_api_jsonrpc.log";
$audit_log_fh = fopen($jsonrpc_audit_log, 'a') or exit();
$data_r = json_decode($data);
$method = strtolower($data_r->method);
$allowed_method = array('apiinfo.version' => false,
'application.get' => false,
'event.get' => false,
'graph.get' => false,
'history.get' => false,
'host.get' => false,
'hostgroup.get' => false,
'item.get' => false,
'map.get' => false,
'trigger.get' => true,
'user.authenticate' => true,
'user.get' => false,
'user.login' => true,
'user.logout' => true);
if(!$allowed_method[$method]){
header('HTTP/1.0 403 Forbidden');
wlog($audit_log_fh, "Method " . $data_r->method . " not accepted");
fclose($audit_log_fh);
exit();
}
if($data_r->params->user){
if(preg_match('/^[a-z]+\.mobile$/', $data_r->params->user)){
wlog($audit_log_fh, "User " . $data_r->params->user. " accepted");
} else{
header('HTTP/1.0 403 Forbidden');
wlog($audit_log_fh, "User " . $data_r->params->user. " not accepted");
fclose($audit_log_fh);
exit();
}
} else{
//wlog($audit_log_fh, "API original request " . $data_r->id . crc32($data_r->auth) . ": " . $data_r->method . "[" . json_encode($data_r->params) . "]");
switch($method){
case 'apiinfo.version':
case 'user.logout':
break;
case 'event.get':
$limit = 10;
break;
case 'trigger.get':
$limit = 25;
$sortfield = "lastchange";
break;
default:
$limit = 5;
break;
}
if ($limit && (!$data_r->params->limit || $data_r->params->limit > $limit))
$data_r->params->limit = "$limit";
if ($sortfield)
$data_r->params->sortfield = "$sortfield";
if ($with_triggers)
$data_r->params->with_triggers = "$with_triggers";
if ($monitored)
$data_r->params->monitored = "$monitored";
wlog($audit_log_fh, "API eventual request " . $data_r->id . crc32($data_r->auth) . ": " . $data_r->method . "[" . json_encode($data_r->params) . "]");
$data = json_encode($data_r);
}
fclose($audit_log_fh);
}
--- SNAP /usr/share/zabbix/api_jsonrpc.php ---